From 214848c75ed93cd23163d2dabe0e7843f019131b Mon Sep 17 00:00:00 2001 From: Andreas Skau Date: Mon, 4 Dec 2023 15:42:01 +0100 Subject: [PATCH 1/5] Add IPMI escape char functionality --- internal/app/wwctl/node/console/power.go | 1 + internal/pkg/api/node/list.go | 3 +- internal/pkg/node/constructors.go | 1 + internal/pkg/node/datastructure.go | 40 +++++++++++++----------- internal/pkg/power/ipmitool.go | 27 ++++++++++------ 5 files changed, 42 insertions(+), 30 deletions(-) diff --git a/internal/app/wwctl/node/console/power.go b/internal/app/wwctl/node/console/power.go index e3be80cb..1f984934 100644 --- a/internal/app/wwctl/node/console/power.go +++ b/internal/app/wwctl/node/console/power.go @@ -56,6 +56,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { Password: node.Ipmi.Password.Get(), AuthType: "MD5", Interface: node.Ipmi.Interface.Get(), + EscapeChar: node.Ipmi.EscapeChar.Get(), } err := ipmiCmd.Console() diff --git a/internal/pkg/api/node/list.go b/internal/pkg/api/node/list.go index 7f79f10c..4f8b27a0 100644 --- a/internal/pkg/api/node/list.go +++ b/internal/pkg/api/node/list.go @@ -64,7 +64,8 @@ func NodeList(nodeGet *wwapiv1.GetNodeList) (nodeList wwapiv1.NodeList, err erro n.Ipmi.Ipaddr.Print(), n.Ipmi.Port.Print(), n.Ipmi.UserName.Print(), - n.Ipmi.Interface.Print())) + n.Ipmi.Interface.Print(), + n.Ipmi.EscapeChar.Print())) } } else if nodeGet.Type == wwapiv1.GetNodeList_Long { nodeList.Output = append(nodeList.Output, diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index 3b4109a4..3512154a 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -263,6 +263,7 @@ func (config *NodeYaml) FindAllProfiles() ([]NodeInfo, error) { p.Ipmi.Password.Set(profile.IpmiPassword) p.Ipmi.Interface.Set(profile.IpmiInterface) p.Ipmi.Write.Set(profile.IpmiWrite) + p.Ipmi.EscapeChar.Set(profile.IpmiEscapeChar) p.Kernel.Args.Set(profile.KernelArgs) p.Kernel.Override.Set(profile.KernelOverride) p.Kernel.Override.Set(profile.KernelVersion) diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index 6eb674a8..9e5faec7 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -54,16 +54,17 @@ type NodeConf struct { } type IpmiConf struct { - UserName string `yaml:"username,omitempty" lopt:"ipmiuser" comment:"Set the IPMI username"` - Password string `yaml:"password,omitempty" lopt:"ipmipass" comment:"Set the IPMI password"` - Ipaddr string `yaml:"ipaddr,omitempty" lopt:"ipmiaddr" comment:"Set the IPMI IP address" type:"IP"` - Netmask string `yaml:"netmask,omitempty" lopt:"ipminetmask" comment:"Set the IPMI netmask" type:"IP"` - Port string `yaml:"port,omitempty" lopt:"ipmiport" comment:"Set the IPMI port"` - Gateway string `yaml:"gateway,omitempty" lopt:"ipmigateway" comment:"Set the IPMI gateway" type:"IP"` - Interface string `yaml:"interface,omitempty" lopt:"ipmiinterface" comment:"Set the node's IPMI interface (defaults: 'lan')"` - Write string `yaml:"write,omitempty" lopt:"ipmiwrite" comment:"Enable the write of impi configuration (true/false)" type:"bool"` - Tags map[string]string `yaml:"tags,omitempty" lopt:"ipmitagadd" comment:"add ipmitags"` - TagsDel []string `yaml:"tagsdel,omitempty" lopt:"ipmitagdel" comment:"remove ipmitags"` // should not go to disk only to wire + UserName string `yaml:"username,omitempty" lopt:"ipmiuser" comment:"Set the IPMI username"` + Password string `yaml:"password,omitempty" lopt:"ipmipass" comment:"Set the IPMI password"` + Ipaddr string `yaml:"ipaddr,omitempty" lopt:"ipmiaddr" comment:"Set the IPMI IP address" type:"IP"` + Netmask string `yaml:"netmask,omitempty" lopt:"ipminetmask" comment:"Set the IPMI netmask" type:"IP"` + Port string `yaml:"port,omitempty" lopt:"ipmiport" comment:"Set the IPMI port"` + Gateway string `yaml:"gateway,omitempty" lopt:"ipmigateway" comment:"Set the IPMI gateway" type:"IP"` + Interface string `yaml:"interface,omitempty" lopt:"ipmiinterface" comment:"Set the node's IPMI interface (defaults: 'lan')"` + EscapeChar string `yaml:"escapechar,omitempty" lopt:"ipmiescapechar" comment:"Set the IPMI escape character (defaults: '~')"` + Write string `yaml:"write,omitempty" lopt:"ipmiwrite" comment:"Enable the write of impi configuration (true/false)" type:"bool"` + Tags map[string]string `yaml:"tags,omitempty" lopt:"ipmitagadd" comment:"add ipmitags"` + TagsDel []string `yaml:"tagsdel,omitempty" lopt:"ipmitagdel" comment:"remove ipmitags"` // should not go to disk only to wire } type KernelConf struct { Version string `yaml:"version,omitempty"` @@ -169,15 +170,16 @@ type NodeInfo struct { } type IpmiEntry struct { - Ipaddr Entry - Netmask Entry - Port Entry - Gateway Entry - UserName Entry - Password Entry - Interface Entry - Write Entry - Tags map[string]*Entry + Ipaddr Entry + Netmask Entry + Port Entry + Gateway Entry + UserName Entry + Password Entry + Interface Entry + EscapeChar Entry + Write Entry + Tags map[string]*Entry } type KernelEntry struct { diff --git a/internal/pkg/power/ipmitool.go b/internal/pkg/power/ipmitool.go index ae647d50..73a5b913 100644 --- a/internal/pkg/power/ipmitool.go +++ b/internal/pkg/power/ipmitool.go @@ -12,14 +12,15 @@ type IPMIResult struct { } type IPMI struct { - NodeName string - HostName string - Port string - User string - Password string - AuthType string - Interface string - result IPMIResult + NodeName string + HostName string + Port string + User string + Password string + AuthType string + Interface string + EscapeChar string + result IPMIResult } func (ipmi *IPMI) Result() (string, error) { @@ -36,7 +37,10 @@ func (ipmi *IPMI) Command(ipmiArgs []string) ([]byte, error) { if ipmi.Port == "" { ipmi.Port = "623" } - args = append(args, "-I", ipmi.Interface, "-H", ipmi.HostName, "-p", ipmi.Port, "-U", ipmi.User, "-P", ipmi.Password) + if ipmi.EscapeChar == "" { + ipmi.EscapeChar = "~" + } + args = append(args, "-I", ipmi.Interface, "-H", ipmi.HostName, "-p", ipmi.Port, "-U", ipmi.User, "-P", ipmi.Password, "-e", ipmi.EscapeChar) args = append(args, ipmiArgs...) ipmiCmd := exec.Command("ipmitool", args...) return ipmiCmd.CombinedOutput() @@ -52,7 +56,10 @@ func (ipmi *IPMI) InteractiveCommand(ipmiArgs []string) error { if ipmi.Port == "" { ipmi.Port = "623" } - args = append(args, "-I", ipmi.Interface, "-H", ipmi.HostName, "-p", ipmi.Port, "-U", ipmi.User, "-P", ipmi.Password) + if ipmi.EscapeChar == "" { + ipmi.EscapeChar = "~" + } + args = append(args, "-I", ipmi.Interface, "-H", ipmi.HostName, "-p", ipmi.Port, "-U", ipmi.User, "-P", ipmi.Password, "-e", ipmi.EscapeChar) args = append(args, ipmiArgs...) ipmiCmd := exec.Command("ipmitool", args...) ipmiCmd.Stdout = os.Stdout From 10976a7e5dda75f8d8c457733ba88eb761d73276 Mon Sep 17 00:00:00 2001 From: Andreas Skau Date: Mon, 4 Dec 2023 15:58:26 +0100 Subject: [PATCH 2/5] Delinted --- internal/pkg/api/node/list.go | 2 +- internal/pkg/node/constructors.go | 1 + internal/pkg/node/datastructure.go | 17 +++++++++-------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/internal/pkg/api/node/list.go b/internal/pkg/api/node/list.go index 4f8b27a0..c8bc35be 100644 --- a/internal/pkg/api/node/list.go +++ b/internal/pkg/api/node/list.go @@ -60,7 +60,7 @@ func NodeList(nodeGet *wwapiv1.GetNodeList) (nodeList wwapiv1.NodeList, err erro fmt.Sprintf("%s:=:%s:=:%s:=:%s:=:%s", "NODE NAME", "IPMI IPADDR", "IPMI PORT", "IPMI USERNAME", "IPMI INTERFACE")) for _, n := range node.FilterByName(nodes, nodeGet.Nodes) { nodeList.Output = append(nodeList.Output, - fmt.Sprintf("%s:=:%s:=:%s:=:%s:=:%s", n.Id.Print(), + fmt.Sprintf("%s:=:%s:=:%s:=:%s:=:%s:=%s", n.Id.Print(), n.Ipmi.Ipaddr.Print(), n.Ipmi.Port.Print(), n.Ipmi.UserName.Print(), diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index 3512154a..25a8944e 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -176,6 +176,7 @@ func (config *NodeYaml) FindAllNodes() ([]NodeInfo, error) { n.Ipmi.UserName.Set(node.IpmiUserName) n.Ipmi.Password.Set(node.IpmiPassword) n.Ipmi.Interface.Set(node.IpmiInterface) + n.Ipmi.EscapeChar.Set(node.Ipmi.EscapeChar) n.Ipmi.Write.Set(node.IpmiWrite) n.Kernel.Args.Set(node.KernelArgs) n.Kernel.Override.Set(node.KernelOverride) diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index 9e5faec7..183e77a1 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -26,14 +26,15 @@ type NodeConf struct { KernelOverride string `yaml:"kernel override,omitempty"` KernelArgs string `yaml:"kernel args,omitempty"` // Ipmi settings herer are deprecated and here for backward compatibility - IpmiUserName string `yaml:"ipmi username,omitempty"` - IpmiPassword string `yaml:"ipmi password,omitempty"` - IpmiIpaddr string `yaml:"ipmi ipaddr,omitempty"` - IpmiNetmask string `yaml:"ipmi netmask,omitempty"` - IpmiPort string `yaml:"ipmi port,omitempty"` - IpmiGateway string `yaml:"ipmi gateway,omitempty"` - IpmiInterface string `yaml:"ipmi interface,omitempty"` - IpmiWrite string `yaml:"ipmi write,omitempty"` + IpmiUserName string `yaml:"ipmi username,omitempty"` + IpmiPassword string `yaml:"ipmi password,omitempty"` + IpmiIpaddr string `yaml:"ipmi ipaddr,omitempty"` + IpmiNetmask string `yaml:"ipmi netmask,omitempty"` + IpmiPort string `yaml:"ipmi port,omitempty"` + IpmiGateway string `yaml:"ipmi gateway,omitempty"` + IpmiInterface string `yaml:"ipmi interface,omitempty"` + IpmiEscapeChar string `yaml:"ipmi escapechar,omitempty"` + IpmiWrite string `yaml:"ipmi write,omitempty"` // Deprecated end RuntimeOverlay []string `yaml:"runtime overlay,omitempty" lopt:"runtime" sopt:"R" comment:"Set the runtime overlay"` SystemOverlay []string `yaml:"system overlay,omitempty" lopt:"wwinit" sopt:"O" comment:"Set the system overlay"` From b574ac03ac0adfd36b7ea6770c30f19bc971a516 Mon Sep 17 00:00:00 2001 From: Andreas Skau Date: Mon, 4 Dec 2023 16:11:10 +0100 Subject: [PATCH 3/5] Went through PR checklist --- CHANGELOG.md | 1 + CONTRIBUTORS.md | 1 + userdocs/contents/ipmi.rst | 3 +++ 3 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2f30884..ae3cce25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Option to change the `ipmitool` escape character - New documentation for the hostlist syntax. #611 - New documentation for development environment (Vagrant) - Ability to duplicate an image with `wwctl container copy` or the API diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 2c7f8020..e43e4c2b 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -29,3 +29,4 @@ * Matt Jolly @Kangie * Arnaud LECOMTE * Ryan Novosielski +* Andreas Skau @buzh diff --git a/userdocs/contents/ipmi.rst b/userdocs/contents/ipmi.rst index 8c8fdec5..86378156 100644 --- a/userdocs/contents/ipmi.rst +++ b/userdocs/contents/ipmi.rst @@ -44,6 +44,8 @@ profile set`` or ``wwctl node set``. +--------------------+---------+------+--------------------+---------------+ | ``--ipmiwrite`` | true | true | true or false | false | +--------------------+---------+------+--------------------+---------------+ +| ``--ipmiescapechar | true | true | single character | ~ | ++--------------------+---------+------+--------------------+---------------+ Reviewing Settings @@ -113,6 +115,7 @@ Node View n001 ipmipass -- -- n001 ipmiinterface -- -- n001 ipmiwrite -- -- + n001 ipmiescapechar -- -- n001 profile -- default n001 default:type -- (ethernet) n001 default:onboot -- -- From 663f2e64ecaa9e03c3d480df09b1ad30ee73fd1d Mon Sep 17 00:00:00 2001 From: Andreas Skau Date: Mon, 4 Dec 2023 22:08:06 +0100 Subject: [PATCH 4/5] Removed deprecated Sets as requested in PR#999 --- internal/pkg/node/constructors.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index 25a8944e..3b4109a4 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -176,7 +176,6 @@ func (config *NodeYaml) FindAllNodes() ([]NodeInfo, error) { n.Ipmi.UserName.Set(node.IpmiUserName) n.Ipmi.Password.Set(node.IpmiPassword) n.Ipmi.Interface.Set(node.IpmiInterface) - n.Ipmi.EscapeChar.Set(node.Ipmi.EscapeChar) n.Ipmi.Write.Set(node.IpmiWrite) n.Kernel.Args.Set(node.KernelArgs) n.Kernel.Override.Set(node.KernelOverride) @@ -264,7 +263,6 @@ func (config *NodeYaml) FindAllProfiles() ([]NodeInfo, error) { p.Ipmi.Password.Set(profile.IpmiPassword) p.Ipmi.Interface.Set(profile.IpmiInterface) p.Ipmi.Write.Set(profile.IpmiWrite) - p.Ipmi.EscapeChar.Set(profile.IpmiEscapeChar) p.Kernel.Args.Set(profile.KernelArgs) p.Kernel.Override.Set(profile.KernelOverride) p.Kernel.Override.Set(profile.KernelVersion) From c635fecbc64055e553333eac279500ffdf602ed8 Mon Sep 17 00:00:00 2001 From: Andreas Skau Date: Mon, 4 Dec 2023 22:18:13 +0100 Subject: [PATCH 5/5] Almost missed a : --- internal/pkg/api/node/list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/pkg/api/node/list.go b/internal/pkg/api/node/list.go index c8bc35be..d27eb412 100644 --- a/internal/pkg/api/node/list.go +++ b/internal/pkg/api/node/list.go @@ -60,7 +60,7 @@ func NodeList(nodeGet *wwapiv1.GetNodeList) (nodeList wwapiv1.NodeList, err erro fmt.Sprintf("%s:=:%s:=:%s:=:%s:=:%s", "NODE NAME", "IPMI IPADDR", "IPMI PORT", "IPMI USERNAME", "IPMI INTERFACE")) for _, n := range node.FilterByName(nodes, nodeGet.Nodes) { nodeList.Output = append(nodeList.Output, - fmt.Sprintf("%s:=:%s:=:%s:=:%s:=:%s:=%s", n.Id.Print(), + fmt.Sprintf("%s:=:%s:=:%s:=:%s:=:%s:=:%s", n.Id.Print(), n.Ipmi.Ipaddr.Print(), n.Ipmi.Port.Print(), n.Ipmi.UserName.Print(),