From 6d3ec350b664f039ad287f7b24353e5ac811a52f Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 16:38:34 -0800 Subject: [PATCH] Updates to nodeStore --- internal/pkg/node/constructors.go | 219 +++++++++++++++++ internal/pkg/node/datastructure.go | 123 ++++++++++ internal/pkg/node/methods.go | 55 +++++ internal/pkg/node/modifiers.go | 209 ++++++++++++++++ internal/pkg/node/modify.go | 222 ----------------- internal/pkg/node/node.go | 377 ----------------------------- 6 files changed, 606 insertions(+), 599 deletions(-) create mode 100644 internal/pkg/node/constructors.go create mode 100644 internal/pkg/node/datastructure.go create mode 100644 internal/pkg/node/methods.go create mode 100644 internal/pkg/node/modifiers.go delete mode 100644 internal/pkg/node/modify.go delete mode 100644 internal/pkg/node/node.go diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go new file mode 100644 index 00000000..ad76b714 --- /dev/null +++ b/internal/pkg/node/constructors.go @@ -0,0 +1,219 @@ +package node + +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/errors" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "gopkg.in/yaml.v2" + "io/ioutil" + "regexp" +) + +func New() (nodeYaml, error) { + var ret nodeYaml + + wwlog.Printf(wwlog.DEBUG, "Opening node configuration file: %s\n", ConfigFile) + data, err := ioutil.ReadFile(ConfigFile) + if err != nil { + fmt.Printf("error reading node configuration file\n") + return ret, err + } + + err = yaml.Unmarshal(data, &ret) + if err != nil { + return ret, err + } + + return ret, nil +} + +func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { + var ret []NodeInfo + + for groupname, group := range self.NodeGroups { + for nodename, node := range group.Nodes { + var n NodeInfo + var allProfiles []string + + if node.Disabled == true || group.Disabled == true { + wwlog.Printf(wwlog.VERBOSE, "Skipping disabled node: %s/%s\n", groupname, nodename) + continue + } + + n.Id = nodename + n.Gid = groupname + n.GroupName = groupname + n.HostName = node.Hostname + n.IpmiIpaddr.Set(node.IpmiIpaddr) + + n.Profiles = node.Profiles + + allProfiles = append(allProfiles, group.Profiles...) + allProfiles = append(allProfiles, node.Profiles...) + + for _, p := range allProfiles { + if _, ok := self.NodeProfiles[p]; !ok { + wwlog.Printf(wwlog.WARN, "Profile not found for node '%s': %s\n", nodename, p) + continue + } + + n.Vnfs.profile = self.NodeProfiles[p].Vnfs + n.KernelVersion.profile = self.NodeProfiles[p].KernelVersion + n.KernelArgs.profile = self.NodeProfiles[p].KernelArgs + n.Ipxe.profile = self.NodeProfiles[p].Ipxe + n.IpmiUserName.profile = self.NodeProfiles[p].IpmiUserName + n.IpmiPassword.profile = self.NodeProfiles[p].IpmiPassword + n.DomainName.profile = self.NodeProfiles[p].DomainName + n.SystemOverlay.profile = self.NodeProfiles[p].SystemOverlay + n.RuntimeOverlay.profile = self.NodeProfiles[p].RuntimeOverlay + } + + n.DomainName.value = node.DomainName + n.DomainName.group = group.DomainName + n.Vnfs.value = node.Vnfs + n.KernelVersion.value = node.KernelVersion + n.KernelArgs.value = node.KernelArgs + n.Ipxe.value = node.Ipxe + n.IpmiUserName.value = node.IpmiUserName + n.IpmiPassword.value = node.IpmiPassword + + n.RuntimeOverlay.def = "default" + n.SystemOverlay.def = "default" + n.Ipxe.def = "default" + n.KernelArgs.def = "crashkernel=no quiet" + + // config := config.New() + // n.VnfsRoot = config.VnfsChroot(vnfs.CleanName(n.Vnfs)) + + if n.DomainName.Defined() == true { + n.Fqdn = n.HostName + "." + n.DomainName.Get() + } else { + n.Fqdn = node.Hostname + } + + n.NetDevs = node.NetDevs + + ret = append(ret, n) + } + } + + return ret, nil +} + +func (self *nodeYaml) FindAllGroups() ([]GroupInfo, error) { + var ret []GroupInfo + + for groupname, group := range self.NodeGroups { + var g GroupInfo + + g.Id = groupname + g.DomainName = group.DomainName + g.Disabled = group.Disabled + g.Comment = group.Comment + + g.Profiles = group.Profiles + + // TODO: Validate or die on all inputs + + ret = append(ret, g) + } + return ret, nil +} + +func (self *nodeYaml) FindAllProfiles() ([]ProfileInfo, error) { + var ret []ProfileInfo + + for name, profile := range self.NodeProfiles { + var p ProfileInfo + + p.Id = name + p.Comment = profile.Comment + p.Vnfs = profile.Vnfs + p.Ipxe = profile.Ipxe + p.KernelVersion = profile.KernelVersion + p.KernelArgs = profile.KernelArgs + p.IpmiUserName = profile.IpmiUserName + p.IpmiPassword = profile.IpmiPassword + p.DomainName = profile.DomainName + p.RuntimeOverlay = profile.RuntimeOverlay + p.SystemOverlay = profile.SystemOverlay + + // TODO: Validate or die on all inputs + + ret = append(ret, p) + } + return ret, nil +} + + + +func (self *nodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) { + var ret NodeInfo + + n, _ := self.FindAllNodes() + + for _, node := range n { + for _, dev := range node.NetDevs { + if dev.Hwaddr == hwa { + return node, nil + } + } + } + + return ret, errors.New("No nodes found with HW Addr: " + hwa) +} + +func (self *nodeYaml) FindByIpaddr(ipaddr string) (NodeInfo, error) { + var ret NodeInfo + + n, _ := self.FindAllNodes() + + for _, node := range n { + for _, dev := range node.NetDevs { + if dev.Ipaddr == ipaddr { + return node, nil + } + } + } + + return ret, errors.New("No nodes found with IP Addr: " + ipaddr) +} + + + + + + + + +func (nodes *nodeYaml) SearchByName(search string) ([]NodeInfo, error) { + var ret []NodeInfo + + n, _ := nodes.FindAllNodes() + + for _, node := range n { + b, _ := regexp.MatchString(search, node.Fqdn) + if b == true { + ret = append(ret, node) + } + } + + return ret, nil +} + +func (nodes *nodeYaml) SearchByNameList(searchList []string) ([]NodeInfo, error) { + var ret []NodeInfo + + n, _ := nodes.FindAllNodes() + + for _, search := range searchList { + for _, node := range n { + b, _ := regexp.MatchString(search, node.Fqdn) + if b == true { + ret = append(ret, node) + } + } + } + + return ret, nil +} diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go new file mode 100644 index 00000000..831ce558 --- /dev/null +++ b/internal/pkg/node/datastructure.go @@ -0,0 +1,123 @@ +package node + +import ( + "github.com/hpcng/warewulf/internal/pkg/util" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "os" +) + +type nodeYaml struct { + NodeProfiles map[string]*ProfileConf + NodeGroups map[string]*GroupConf +} + +type ProfileConf struct { + Comment string `yaml:"comment"` + Vnfs string `yaml:"vnfs,omitempty"` + Ipxe string `yaml:"ipxe template,omitempty"` + KernelVersion string `yaml:"kernel version,omitempty"` + KernelArgs string `yaml:"kernel args,omitempty"` + IpmiUserName string `yaml:"ipmi username,omitempty"` + IpmiPassword string `yaml:"ipmi password,omitempty"` + DomainName string `yaml:"domain name,omitempty"` + RuntimeOverlay string `yaml:"runtime overlay files,omitempty"` + SystemOverlay string `yaml:"system overlay files,omitempty"` +} + +type GroupConf struct { + Comment string `yaml:"comment"` + Disabled bool `yaml:"disabled,omitempty"` + DomainName string `yaml:"domain name"` + Profiles []string `yaml:"profiles,omitempty"` + Nodes map[string]*NodeConf +} + +type NodeConf struct { + Comment string `yaml:"comment,omitempty"` + Disabled bool `yaml:"disabled,omitempty"` + Hostname string `yaml:"hostname,omitempty"` + Vnfs string `yaml:"vnfs,omitempty"` + Ipxe string `yaml:"ipxe template,omitempty"` + KernelVersion string `yaml:"kernel version,omitempty"` + KernelArgs string `yaml:"kernel args,omitempty"` + IpmiUserName string `yaml:"ipmi username,omitempty"` + IpmiPassword string `yaml:"ipmi password,omitempty"` + DomainName string `yaml:"domain name,omitempty"` + IpmiIpaddr string `yaml:"ipmi ipaddr,omitempty"` + RuntimeOverlay string `yaml:"runtime overlay files,omitempty"` + SystemOverlay string `yaml:"system overlay files,omitempty"` + Profiles []string `yaml:"profiles,omitempty"` + NetDevs map[string]*NetDevs +} + +type NetDevs struct { + Type string `yaml:"type,omitempty"` + Hwaddr string + Ipaddr string + Netmask string + Gateway string `yaml:"gateway,omitempty"` +} + +type NodeInfoEntry struct { + value string + profile string + group string + def string +} + +type NodeInfo struct { + Id string + Gid string + Uid string + Comment string + GroupName string + HostName string + Fqdn string + DomainName NodeInfoEntry + Vnfs NodeInfoEntry + VnfsRoot NodeInfoEntry + Ipxe NodeInfoEntry + KernelVersion NodeInfoEntry + KernelArgs NodeInfoEntry + IpmiIpaddr NodeInfoEntry + IpmiUserName NodeInfoEntry + IpmiPassword NodeInfoEntry + RuntimeOverlay NodeInfoEntry + SystemOverlay NodeInfoEntry + Profiles []string + NetDevs map[string]*NetDevs +} + +type GroupInfo struct { + Id string + Comment string + Disabled bool + DomainName string + Profiles []string +} + +type ProfileInfo struct { + Id string + Comment string + Vnfs string + Ipxe string + KernelVersion string + KernelArgs string + IpmiUserName string + IpmiPassword string + DomainName string + RuntimeOverlay string + SystemOverlay string +} + + + +const ConfigFile = "/etc/warewulf/nodes.conf" + +func init() { + //TODO: Check to make sure nodes.conf is found + if util.IsFile(ConfigFile) == false { + wwlog.Printf(wwlog.ERROR, "Configuration file not found: %s\n", ConfigFile) + os.Exit(1) + } +} diff --git a/internal/pkg/node/methods.go b/internal/pkg/node/methods.go new file mode 100644 index 00000000..93e12b54 --- /dev/null +++ b/internal/pkg/node/methods.go @@ -0,0 +1,55 @@ +package node + +func (self *NodeInfoEntry) String() string { + if self.value != "" { + return "node=" + self.value + } + if self.group != "" { + return "group=" + self.group + } + if self.profile != "" { + return "profile=" + self.profile + } + if self.def != "" { + return "default=" + self.def + } + return "--" +} + +func (self *NodeInfoEntry) Get() string { + if self.value != "" { + return self.value + } + if self.group != "" { + return self.group + } + if self.profile != "" { + return self.profile + } + if self.def != "" { + return self.def + } + return "" +} + +func (self *NodeInfoEntry) Defined() bool { + if self.Get() == "" { + return false + } + return true +} + +func (self *NodeInfoEntry) Set(value string) { + if value == "" { + return + } + self.value = value +} + +func (self *NodeInfoEntry) Unset() { + self.value = "" +} + +func (self *NodeInfoEntry) GetReal() string { + return self.value +} \ No newline at end of file diff --git a/internal/pkg/node/modifiers.go b/internal/pkg/node/modifiers.go new file mode 100644 index 00000000..014a9dca --- /dev/null +++ b/internal/pkg/node/modifiers.go @@ -0,0 +1,209 @@ +package node + +import ( + "github.com/hpcng/warewulf/internal/pkg/errors" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + + "gopkg.in/yaml.v2" + "os" +) + +/**** + * + * NODE MODIFIERS + * +****/ + +func (self *nodeYaml) AddNode(groupID string, nodeID string) error { + var node NodeConf + + wwlog.Printf(wwlog.VERBOSE, "Adding new node: %s/%s\n", groupID, nodeID) + + if _, ok := self.NodeGroups[groupID]; !ok { + return errors.New("Group does not exist: " + groupID) + } + + if _, ok := self.NodeGroups[groupID].Nodes[groupID]; ok { + return errors.New("Nodename already exists in group: " + nodeID) + } + + self.NodeGroups[groupID].Nodes[nodeID] = &node + self.NodeGroups[groupID].Nodes[nodeID].Hostname = nodeID + + return nil +} + +func (self *nodeYaml) DelNode(groupID string, nodeID string) error { + + if _, ok := self.NodeGroups[groupID]; !ok { + return errors.New("Group '" + groupID + "' was not found") + } + if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; !ok { + return errors.New("Node '" + nodeID + "' was not found in group '" + groupID + "'") + } + + wwlog.Printf(wwlog.VERBOSE, "Deleting node network device: %s/%s\n", groupID, nodeID) + delete(self.NodeGroups[groupID].Nodes, nodeID) + + return nil +} + +func(self *nodeYaml) NodeUpdate(node NodeInfo) error { + groupID := node.Gid + nodeID := node.Id + + if _, ok := self.NodeGroups[groupID]; !ok { + return errors.New("Group '" + groupID + "' was not found") + } + if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; !ok { + return errors.New("Node '" + nodeID + "' was not found in group '" + groupID + "'") + } + + self.NodeGroups[groupID].Nodes[nodeID].Hostname = node.HostName + self.NodeGroups[groupID].Nodes[nodeID].Vnfs = node.Vnfs.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].DomainName = node.DomainName.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].Ipxe = node.Ipxe.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].KernelVersion = node.KernelVersion.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].KernelArgs = node.KernelArgs.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].IpmiIpaddr = node.IpmiIpaddr.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].IpmiUserName = node.IpmiUserName.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].IpmiPassword = node.IpmiPassword.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].RuntimeOverlay = node.RuntimeOverlay.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].SystemOverlay = node.SystemOverlay.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].Profiles = node.Profiles + self.NodeGroups[groupID].Nodes[nodeID].NetDevs = node.NetDevs + + return nil +} + + + +/**** + * + * GROUP MODIFIERS + * +****/ + +func (self *nodeYaml) AddGroup(groupID string) error { + var group GroupConf + + wwlog.Printf(wwlog.VERBOSE, "Adding new group: %s/%s\n", groupID) + + if _, ok := self.NodeGroups[groupID]; ok { + return errors.New("Group name already exists: " + groupID) + } + + self.NodeGroups[groupID] = &group + self.NodeGroups[groupID].DomainName = groupID + + return nil +} + +func (self *nodeYaml) DelGroup(groupID string) error { + if _, ok := self.NodeGroups[groupID]; !ok { + + return errors.New("Group '" + groupID + "' was not found") + } + + wwlog.Printf(wwlog.VERBOSE, "Deleting group: %s\n", groupID) + delete(self.NodeGroups, groupID) + + return nil +} + +func(self *nodeYaml) GroupUpdate(group GroupInfo) error { + groupID := group.Id + + if _, ok := self.NodeGroups[groupID]; !ok { + return errors.New("Group '" + groupID + "' was not found") + } + + self.NodeGroups[groupID].DomainName = group.DomainName + + return nil +} + + + + +/**** + * + * PROFILE MODIFIERS + * +****/ + +func (self *nodeYaml) AddProfile(profileID string) error { + var profile ProfileConf + + wwlog.Printf(wwlog.VERBOSE, "Adding new profile: %s/%s\n", profileID) + + if _, ok := self.NodeProfiles[profileID]; ok { + return errors.New("Profile name already exists: " + profileID) + } + + self.NodeProfiles[profileID] = &profile + + return nil +} + +func (self *nodeYaml) DelProfile(profileID string) error { + if _, ok := self.NodeProfiles[profileID]; ! ok { + return errors.New("Group '" + profileID + "' was not found") + } + + wwlog.Printf(wwlog.VERBOSE, "Deleting profile: %s\n", profileID) + delete(self.NodeProfiles, profileID) + + return nil +} + +func(self *nodeYaml) ProfileUpdate(profile ProfileInfo) error { + profileID := profile.Id + + if _, ok := self.NodeProfiles[profileID]; ! ok { + return errors.New("Group '" + profileID + "' was not found") + } + + self.NodeProfiles[profileID].DomainName = profile.DomainName + self.NodeProfiles[profileID].Vnfs = profile.Vnfs + self.NodeProfiles[profileID].Ipxe = profile.Ipxe + self.NodeProfiles[profileID].KernelVersion = profile.KernelVersion + self.NodeProfiles[profileID].IpmiUserName = profile.IpmiUserName + self.NodeProfiles[profileID].IpmiPassword = profile.IpmiPassword + self.NodeProfiles[profileID].RuntimeOverlay = profile.RuntimeOverlay + self.NodeProfiles[profileID].SystemOverlay = profile.SystemOverlay + + return nil +} + + + + +/**** + * + * PERSISTENCE + * +****/ + +func (self *nodeYaml) Persist() error { + + out, err := yaml.Marshal(self) + if err != nil { + return err + } + + file, err := os.OpenFile(ConfigFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + defer file.Close() + + _, err = file.WriteString(string(out)) + if err != nil { + return err + } + + return nil +} diff --git a/internal/pkg/node/modify.go b/internal/pkg/node/modify.go deleted file mode 100644 index e120f777..00000000 --- a/internal/pkg/node/modify.go +++ /dev/null @@ -1,222 +0,0 @@ -package node - -import ( - "github.com/hpcng/warewulf/internal/pkg/errors" - "github.com/hpcng/warewulf/internal/pkg/util" - "github.com/hpcng/warewulf/internal/pkg/wwlog" - - "gopkg.in/yaml.v2" - "os" - "strings" -) - -func (self *nodeYaml) AddGroup(groupID string) error { - var group nodeGroup - - if _, ok := self.NodeGroups[groupID]; ok { - return errors.New("Group name already exists: " + groupID) - } - - self.NodeGroups[groupID] = &group - self.NodeGroups[groupID].DomainSuffix = groupID - - return nil -} - -func (self *nodeYaml) AddNode(groupID string, nodeID string) error { - var node nodeEntry - - wwlog.Printf(wwlog.VERBOSE, "Adding new node: %s/%s\n", groupID, nodeID) - - if _, ok := self.NodeGroups[groupID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { - return errors.New("Nodename already exists in group: " + nodeID) - } - } else { - return errors.New("Group does not exist: "+groupID) - } - - self.NodeGroups[groupID].Nodes[nodeID] = &node - self.NodeGroups[groupID].Nodes[nodeID].Hostname = nodeID - - return nil -} - -func (self *nodeYaml) DelNode(groupID string, nodeID string) error { - - if _, ok := self.NodeGroups[groupID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { - delete(self.NodeGroups[groupID].Nodes, nodeID) - wwlog.Printf(wwlog.VERBOSE, "Deleting node: %s/%s\n", groupID, nodeID) - } else { - return errors.New("Node '"+nodeID+"' was not found in group '"+groupID+"'") - } - } else { - return errors.New("Group '"+groupID+"' was not found") - } - - return nil -} - -func (self *nodeYaml) DelNodeNet(groupID string, nodeID string, netDev string) error { - - if _, ok := self.NodeGroups[groupID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev]; ok { - wwlog.Printf(wwlog.VERBOSE, "Deleting node network device: %s/%s:%s\n", groupID, nodeID, netDev) - delete(self.NodeGroups[groupID].Nodes[nodeID].NetDevs, netDev) - } else { - return errors.New("Network device '"+netDev+"' was not found in node '"+groupID+"/"+nodeID+"'") - } - } else { - return errors.New("Node '"+nodeID+"' was not found in group '"+groupID+"'") - } - } else { - return errors.New("Group '"+groupID+"' was not found") - } - - return nil -} - - -func (self *nodeYaml) DelGroup(groupname string) error { - if _, ok := self.NodeGroups[groupname]; ok { - delete(self.NodeGroups, groupname) - } else { - return errors.New("Node group undefined: " + groupname) - } - - return nil -} - -func (self *nodeYaml) SetGroupVal(groupID string, entry string, value string) error { - if strings.ToUpper(value) == "UNDEF" || strings.ToUpper(value) == "NIL" || strings.ToUpper(value) == "DEL" { - value = "" - } - - if _, ok := self.NodeGroups[groupID]; ok { - wwlog.Printf(wwlog.VERBOSE, "Setting group %s to: %s = '%s'\n", groupID, entry, value ) - - switch strings.ToUpper(entry) { - case "DOMAINSUFFIX": - util.ValidateOrDie("Domain", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].DomainSuffix = value - } - - } else { - return errors.New("Group does not exist: " +groupID) - } - - return nil -} - -func (self *nodeYaml) SetNodeVal(groupID string, nodeID string, entry string, value string) error { - if strings.ToUpper(value) == "UNDEF" || strings.ToUpper(value) == "NIL" || strings.ToUpper(value) == "DEL" { - value = "" - } - if _, ok := self.NodeGroups[groupID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { - wwlog.Printf(wwlog.VERBOSE, "Setting node %s/%s to: %s = '%s'\n", groupID, nodeID, entry, value ) - - switch strings.ToUpper(entry) { - case "VNFS": - util.ValidateOrDie("VNFS", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].Vnfs = value - case "KERNEL": - util.ValidateOrDie("Kernel Version", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].KernelVersion = value - case "DOMAINSUFFIX": - util.ValidateOrDie("Domain", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].DomainSuffix = value - case "IPXE": - util.ValidateOrDie("iPXE Template", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].Ipxe = value - case "HOSTNAME": - util.ValidateOrDie("Hostname", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].Hostname = value - case "IPMIIPADDR": - util.ValidateOrDie("IPMI IP Address", entry, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") - self.NodeGroups[groupID].Nodes[nodeID].IpmiIpaddr = value - case "IPMIUSERNAME": - util.ValidateOrDie("IPMI Username", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].IpmiUserName = value - case "IPMIPASSWORD": - util.ValidateOrDie("IPMI Password", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].IpmiPassword = value - - } - } else { - return errors.New("Node does not exist: " +groupID+ "/" +nodeID) - } - } else { - return errors.New("Group does not exist: " +groupID) - } - - return nil -} - -func (self *nodeYaml) SetNodeNet(groupID string, nodeID string, netDev string, entry string, value string) error { - if strings.ToUpper(value) == "UNDEF" || strings.ToUpper(value) == "NIL" || strings.ToUpper(value) == "DEL" { - value = "" - } - - if _, ok := self.NodeGroups[groupID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev]; ok { - wwlog.Printf(wwlog.VERBOSE, "Editing existing node NetDev entry for node: %s/%s\n", groupID, nodeID) - } else { - var nd NetDevs - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev] = &nd - } - } else { - return errors.New("Node does not exist: "+groupID+"/"+nodeID) - } - } else { - return errors.New("Group does not exist: "+groupID) - } - - switch strings.ToUpper(entry) { - case "IPADDR": - util.ValidateOrDie("IP address", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Ipaddr = value - case "NETMASK": - util.ValidateOrDie("Netmask", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Netmask = value - case "GATEWAY": - util.ValidateOrDie("Gateway", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Gateway = value - case "TYPE": - util.ValidateOrDie("Network device type", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Type = value - case "HWADDR": - util.ValidateOrDie("HW address", value, "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$") - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Hwaddr = value - - } - - return nil -} - -func (self *nodeYaml) Persist() error { - - out, err := yaml.Marshal(self) - if err != nil { - return err - } - - file, err := os.OpenFile(ConfigFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - - defer file.Close() - - _, err = file.WriteString(string(out)) - if err != nil { - return err - } - - return nil -} - diff --git a/internal/pkg/node/node.go b/internal/pkg/node/node.go deleted file mode 100644 index 139c435c..00000000 --- a/internal/pkg/node/node.go +++ /dev/null @@ -1,377 +0,0 @@ -package node - -import ( - "fmt" - "github.com/hpcng/warewulf/internal/pkg/config" - "github.com/hpcng/warewulf/internal/pkg/errors" - "github.com/hpcng/warewulf/internal/pkg/vnfs" - "github.com/hpcng/warewulf/internal/pkg/wwlog" - "gopkg.in/yaml.v2" - "io/ioutil" - "regexp" -) - -const ConfigFile = "/etc/warewulf/nodes.conf" - -func init() { - //TODO: Check to make sure nodes.conf is found - -} - -type nodeYaml struct { - Profiles map[string]*profileConfig - NodeGroups map[string]*nodeGroup - Hwaddrs map[string]NodeInfo -} - -type profileConfig struct { - Vnfs string `yaml:"vnfs"` - Ipxe string `yaml:"ipxe template,omitempty"` - KernelVersion string `yaml:"kernel version"` - KernelArgs string `yaml:"kernel args"` - IpmiUserName string `yaml:"ipmi username,omitempty"` - IpmiPassword string `yaml:"ipmi password,omitempty"` - DomainSuffix string `yaml:"domain suffix,omitempty"` - RuntimeOverlay []OverlayEntry `yaml:"runtime overlay files,omitempty"` - SystemOverlay []OverlayEntry `yaml:"system overlay files,omitempty"` -} - -type OverlayEntry struct { - Path string `yaml:"path,omitempty"` - File bool `yaml:"file,omitempty"` - Dir bool `yaml:"dir,omitempty"` - Link bool `yaml:"link,omitempty"` - Template bool `yaml:"template,omitempty"` - Mode int32 `yaml:"mode,omitempty"` - Owner string `yaml:"owner,omitempty"` - Group string `yaml:"group,omitempty"` - Source string `yaml:"source,omitempty"` - Sources []string `yaml:"sources,omitempty"` -} - -type nodeGroup struct { - Comment string - DomainSuffix string `yaml:"domain suffix"` - Profiles []string `yaml:"profiles"` - Nodes map[string]*nodeEntry -} - -type nodeEntry struct { - Hostname string `yaml:"hostname,omitempty"` - Vnfs string `yaml:"vnfs"` - Ipxe string `yaml:"ipxe template,omitempty"` - KernelVersion string `yaml:"kernel version"` - KernelArgs string `yaml:"kernel args"` - IpmiUserName string `yaml:"ipmi username,omitempty"` - IpmiPassword string `yaml:"ipmi password,omitempty"` - DomainSuffix string `yaml:"domain suffix,omitempty"` - IpmiIpaddr string `yaml:"ipmi ipaddr,omitempty"` - Profiles []string `yaml:"profiles"` - RuntimeOverlay []OverlayEntry `yaml:"system overlay files,omitempty"` - SystemOverlay []OverlayEntry `yaml:"runtime overlay files,omitempty"` - NetDevs map[string]*NetDevs -} - -type NetDevs struct { - Type string `yaml:"type,omitempty"` - Hwaddr string - Ipaddr string - Netmask string - Gateway string `yaml:"gateway,omitempty"` -} - -type EntryInfo struct { - Value string - override string - def string -} - -type NodeInfo struct { - Id string - Gid string - Uid string - GroupName string - HostName string - DomainName string - Fqdn string - Vnfs string - VnfsRoot string - Ipxe string - KernelVersion string - KernelArgs string - IpmiIpaddr string - IpmiUserName string - IpmiPassword string - Profiles []string - RuntimeOverlay []OverlayEntry - SystemOverlay []OverlayEntry - NetDevs map[string]*NetDevs -} - -type GroupInfo struct { - Id string - GroupName string - DomainName string - Vnfs string - Ipxe string - SystemOverlay string - RuntimeOverlay string - KernelVersion string - KernelArgs string - IpmiUserName string - IpmiPassword string -} - - - -func (i *EntryInfo) Default (value string) { - if value == "" { - return - } - i.def = value -} - -func (i *EntryInfo) Set (value string) { - if value == "" { - return - } - i.Value = value - i.override = "" -} - -func (i *EntryInfo) Override (value string) { - if value == "" { - return - } - i.override = value -} - -func (i *EntryInfo) String () string { - if i.override != "" { - return i.override - } else if i.Value != "" { - return i.Value - } - return i.def -} - -func (i *EntryInfo) Defined () bool { - if i.String() == "" { - return false - } - return true -} - -func (i *EntryInfo) Fprint () string { - if i.override != "" { - return "["+ i.override +"]" - } else if i.Value != "" { - return i.Value - } else if i.def != "" { - return "("+ i.def +")" - } - return "--" -} - -func New() (nodeYaml, error) { - var ret nodeYaml - - wwlog.Printf(wwlog.DEBUG, "Opening node configuration file: %s\n", ConfigFile) - data, err := ioutil.ReadFile(ConfigFile) - if err != nil { - fmt.Printf("error reading node configuration file\n") - return ret, err - } - - err = yaml.Unmarshal(data, &ret) - if err != nil { - return ret, err - } - - return ret, nil -} - - -func (self *nodeYaml) FindAllGroups() ([]GroupInfo, error) { - var ret []GroupInfo - - for groupname, group := range self.NodeGroups { - var g GroupInfo - - g.Id = groupname - g.GroupName = groupname - g.DomainName = group.DomainSuffix - - // TODO: Validate or die on all inputs - - ret = append(ret, g) - } - return ret, nil -} - - -func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { - var ret []NodeInfo - - for groupname, group := range self.NodeGroups { - for nodename, node := range group.Nodes { - var n NodeInfo - - n.Id = nodename - n.Gid = groupname - n.GroupName = groupname - n.HostName = node.Hostname - n.Profiles = node.Profiles - n.IpmiIpaddr = node.IpmiIpaddr - - if len(n.Profiles) == 0 { - n.Profiles = append(n.Profiles, "default") - } - - for _, p := range n.Profiles { - if _, ok := self.Profiles[p]; ok { - } else { - continue - } - if self.Profiles[p].Vnfs != "" { - n.Vnfs = self.Profiles[p].Vnfs - } - if self.Profiles[p].KernelVersion != "" { - n.KernelVersion = self.Profiles[p].KernelVersion - } - if self.Profiles[p].KernelArgs != "" { - n.KernelArgs = self.Profiles[p].KernelArgs - } - if self.Profiles[p].Ipxe != "" { - n.Ipxe = self.Profiles[p].Ipxe - } - if self.Profiles[p].IpmiUserName != "" { - n.IpmiUserName = self.Profiles[p].IpmiUserName - } - if self.Profiles[p].IpmiPassword != "" { - n.IpmiPassword = self.Profiles[p].IpmiPassword - } - if self.Profiles[p].DomainSuffix != "" { - n.DomainName = self.Profiles[p].DomainSuffix - } - - for _, ro := range self.Profiles[p].RuntimeOverlay { - n.RuntimeOverlay = append(n.RuntimeOverlay, ro) - } - for _, so := range self.Profiles[p].SystemOverlay { - n.SystemOverlay = append(n.SystemOverlay, so) - } - } - - if node.DomainSuffix != "" { - n.DomainName = node.DomainSuffix - } else if group.DomainSuffix != "" { - n.DomainName = group.DomainSuffix - } - if node.Vnfs != "" { - n.Vnfs = node.Vnfs - } - if node.KernelVersion != "" { - n.KernelVersion = node.KernelVersion - } - if node.KernelArgs != "" { - n.KernelArgs = node.KernelArgs - } - if node.Ipxe != "" { - n.Ipxe = node.Ipxe - } - if node.IpmiUserName != "" { - n.IpmiUserName = node.IpmiUserName - } - if node.IpmiPassword != "" { - n.IpmiPassword = node.IpmiPassword - } - - if n.Ipxe == "" { - n.Ipxe = "default" - } - if n.KernelArgs == "" { - n.KernelArgs = "crashkernel=no quiet" - } - - config := config.New() - n.VnfsRoot = config.VnfsChroot(vnfs.CleanName(n.Vnfs)) - - if n.DomainName != "" { - n.Fqdn = node.Hostname + "." + n.DomainName - } else { - n.Fqdn = node.Hostname - } - - n.NetDevs = node.NetDevs - - ret = append(ret, n) - } - } - - return ret, nil -} - -func (self *nodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) { - var ret NodeInfo - - n, _ := self.FindAllNodes() - - for _, node := range n { - for _, dev := range node.NetDevs { - if dev.Hwaddr == hwa { - return node, nil - } - } - } - - return ret, errors.New("No nodes found with HW Addr: " + hwa) -} - -func (self *nodeYaml) FindByIpaddr(ipaddr string) (NodeInfo, error) { - var ret NodeInfo - - n, _ := self.FindAllNodes() - - for _, node := range n { - for _, dev := range node.NetDevs { - if dev.Ipaddr == ipaddr { - return node, nil - } - } - } - - return ret, errors.New("No nodes found with IP Addr: " + ipaddr) -} - -func (nodes *nodeYaml) SearchByName(search string) ([]NodeInfo, error) { - var ret []NodeInfo - - n, _ := nodes.FindAllNodes() - - for _, node := range n { - b, _ := regexp.MatchString(search, node.Fqdn) - if b == true { - ret = append(ret, node) - } - } - - return ret, nil -} - -func (nodes *nodeYaml) SearchByNameList(searchList []string) ([]NodeInfo, error) { - var ret []NodeInfo - - n, _ := nodes.FindAllNodes() - - for _, search := range searchList { - for _, node := range n { - b, _ := regexp.MatchString(search, node.Fqdn) - if b == true { - ret = append(ret, node) - } - } - } - - return ret, nil -} \ No newline at end of file