diff --git a/.devcontainer/.env b/.devcontainer/.env new file mode 100644 index 0000000..15181a6 --- /dev/null +++ b/.devcontainer/.env @@ -0,0 +1,4 @@ +POSTGRES_USER=postgres +POSTGRES_PASSWORD=postgres +POSTGRES_DB=postgres +POSTGRES_HOSTNAME=localhost diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..d557f51 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,13 @@ +FROM mcr.microsoft.com/devcontainers/go:1-1.20-bullseye + +# [Optional] Uncomment this section to install additional OS packages. +# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ +# && apt-get -y install --no-install-recommends + +# [Optional] Uncomment the next lines to use go get to install anything else you need +# USER vscode +# RUN go get -x +# USER root + +# [Optional] Uncomment this line to install global node packages. +# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g " 2>&1 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..f767ed3 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,28 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/go-postgres +{ + "name": "Go & PostgreSQL", + "dockerComposeFile": "docker-compose.yml", + "service": "app", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + "features": { + "ghcr.io/marcozac/devcontainer-features/goreleaser:1": {}, + "ghcr.io/devcontainers/features/docker-in-docker:2": {} + + } + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Configure tool-specific properties. + // "customizations": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [5432], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "go version", + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 0000000..071a939 --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -0,0 +1,38 @@ +version: '3.8' + +volumes: + postgres-data: + +services: + app: + build: + context: . + dockerfile: Dockerfile + env_file: + # Ensure that the variables in .env match the same variables in devcontainer.json + - .env + + volumes: + - ../..:/workspaces:cached + + # Overrides default command so things don't shut down after the process ends. + command: sleep infinity + + # Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function. + network_mode: service:db + + # Use "forwardPorts" in **devcontainer.json** to forward an app port locally. + # (Adding the "ports" property to this file will not forward from a Codespace.) + + db: + image: postgres:latest + restart: unless-stopped + volumes: + - postgres-data:/var/lib/postgresql/data + env_file: + # Ensure that the variables in .env match the same variables in devcontainer.json + - .env + + + # Add "forwardPorts": ["5432"] to **devcontainer.json** to forward PostgreSQL locally. + # (Adding the "ports" property to this file will not forward from a Codespace.) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 26482d3..427410a 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -10,10 +10,10 @@ builds: - amd64 dockers: - image_templates: - - bikeshack/{{.ProjectName}}:latest - - bikeshack/{{.ProjectName}}:{{ .Tag }} - - bikeshack/{{.ProjectName}}:{{ .Major }} - - bikeshack/{{.ProjectName}}:{{ .Major }}.{{ .Minor }} + - ghcr.io/openchami/{{.ProjectName}}:latest + - ghcr.io/openchami/{{.ProjectName}}:{{ .Tag }} + - ghcr.io/openchami/{{.ProjectName}}:{{ .Major }} + - ghcr.io/openchami/{{.ProjectName}}:{{ .Major }}.{{ .Minor }} build_flag_templates: - "--pull" - "--label=org.opencontainers.image.created={{.Date}}" diff --git a/CHANGELOG.md b/CHANGELOG.md index 701718f..f999cdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] + + +## [0.0.5] - 2023-11-02 + +### Added + + * Ability to update firmware + * Refactored connection handling for faster scanning + * Updated to refelct home at github.com/OpenCHAMI + * Updated to reflect ghcr.io as container home + + ## [Unreleased] ## [0.0.1] - 2023-09-14 diff --git a/cmd/collect.go b/cmd/collect.go index 273de4a..e38cfe0 100644 --- a/cmd/collect.go +++ b/cmd/collect.go @@ -1,10 +1,10 @@ package cmd import ( - magellan "github.com/OpenChami/magellan/internal" - "github.com/OpenChami/magellan/internal/api/smd" - "github.com/OpenChami/magellan/internal/db/sqlite" - "github.com/OpenChami/magellan/internal/log" + magellan "github.com/OpenCHAMI/magellan/internal" + "github.com/OpenCHAMI/magellan/internal/api/smd" + "github.com/OpenCHAMI/magellan/internal/db/sqlite" + "github.com/OpenCHAMI/magellan/internal/log" "github.com/cznic/mathutil" "github.com/sirupsen/logrus" "github.com/spf13/cobra" diff --git a/cmd/list.go b/cmd/list.go index 655aea8..9ad54bb 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -3,7 +3,7 @@ package cmd import ( "fmt" - "github.com/OpenChami/magellan/internal/db/sqlite" + "github.com/OpenCHAMI/magellan/internal/db/sqlite" "github.com/sirupsen/logrus" "github.com/spf13/cobra" diff --git a/cmd/scan.go b/cmd/scan.go index 02c366f..127b11e 100644 --- a/cmd/scan.go +++ b/cmd/scan.go @@ -6,18 +6,18 @@ import ( "os" "path" - magellan "github.com/OpenChami/magellan/internal" - "github.com/OpenChami/magellan/internal/db/sqlite" + magellan "github.com/OpenCHAMI/magellan/internal" + "github.com/OpenCHAMI/magellan/internal/db/sqlite" "github.com/cznic/mathutil" "github.com/spf13/cobra" ) var ( - begin uint8 - end uint8 - subnets []string - subnetMasks []net.IP + begin uint8 + end uint8 + subnets []string + subnetMasks []net.IP disableProbing bool ) @@ -35,10 +35,10 @@ var scanCmd = &cobra.Command{ return } - if len(subnetMasks) < i + 1 { + if len(subnetMasks) < i+1 { subnetMasks = append(subnetMasks, net.IP{255, 255, 255, 0}) } - + hostsToScan = append(hostsToScan, magellan.GenerateHosts(subnet, &subnetMasks[i])...) } } diff --git a/cmd/update.go b/cmd/update.go index ce2e4da..94ccd71 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -1,45 +1,45 @@ package cmd import ( - magellan "github.com/OpenChami/magellan/internal" - "github.com/OpenChami/magellan/internal/log" + magellan "github.com/OpenCHAMI/magellan/internal" + "github.com/OpenCHAMI/magellan/internal/log" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) var ( - host string - port int - firmwareUrl string - firmwareVersion string - component string + host string + port int + firmwareUrl string + firmwareVersion string + component string transferProtocol string - status bool + status bool ) var updateCmd = &cobra.Command{ - Use: "update", + Use: "update", Short: "Update BMC node firmware", Run: func(cmd *cobra.Command, args []string) { l := log.NewLogger(logrus.New(), logrus.DebugLevel) - q := &magellan.UpdateParams { - FirmwarePath: firmwareUrl, - FirmwareVersion: firmwareVersion, - Component: component, + q := &magellan.UpdateParams{ + FirmwarePath: firmwareUrl, + FirmwareVersion: firmwareVersion, + Component: component, TransferProtocol: transferProtocol, QueryParams: magellan.QueryParams{ - Drivers: []string{"redfish"}, - Preferred: "redfish", - Protocol: protocol, - Host: host, - User: user, - Pass: pass, - Timeout: timeout, - Port: port, + Drivers: []string{"redfish"}, + Preferred: "redfish", + Protocol: protocol, + Host: host, + User: user, + Pass: pass, + Timeout: timeout, + Port: port, WithSecureTLS: withSecureTLS, }, } - + // check if required params are set if host == "" || user == "" || pass == "" { l.Log.Fatal("requires host, user, and pass to be set") @@ -53,7 +53,7 @@ var updateCmd = &cobra.Command{ } return } - + // client, err := magellan.NewClient(l, &q.QueryParams) // if err != nil { // l.Log.Errorf("could not make client: %v", err) @@ -79,4 +79,4 @@ func init() { updateCmd.Flags().BoolVar(&withSecureTLS, "secure-tls", false, "enable secure TLS") updateCmd.Flags().BoolVar(&status, "status", false, "get the status of the update") rootCmd.AddCommand(updateCmd) -} \ No newline at end of file +} diff --git a/go.mod b/go.mod index 3f4f136..1b5ea7b 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/OpenChami/magellan +module github.com/OpenCHAMI/magellan go 1.20 diff --git a/internal/api/dora/dora.go b/internal/api/dora/dora.go index 880fc4a..880ac7b 100644 --- a/internal/api/dora/dora.go +++ b/internal/api/dora/dora.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/OpenChami/magellan/internal/util" + "github.com/OpenCHAMI/magellan/internal/util" "github.com/jmoiron/sqlx" ) diff --git a/internal/api/smd/smd.go b/internal/api/smd/smd.go index a3e9f66..ca0a606 100644 --- a/internal/api/smd/smd.go +++ b/internal/api/smd/smd.go @@ -6,7 +6,7 @@ package smd import ( "fmt" - "github.com/OpenChami/magellan/internal/util" + "github.com/OpenCHAMI/magellan/internal/util" // hms "github.com/alexlovelltroy/hms-smd" ) diff --git a/internal/collect.go b/internal/collect.go index 4a0e0cb..b00ee63 100644 --- a/internal/collect.go +++ b/internal/collect.go @@ -12,10 +12,10 @@ import ( "sync" "time" - "github.com/OpenChami/magellan/internal/log" + "github.com/OpenCHAMI/magellan/internal/log" - "github.com/OpenChami/magellan/internal/api/smd" - "github.com/OpenChami/magellan/internal/util" + "github.com/OpenCHAMI/magellan/internal/api/smd" + "github.com/OpenCHAMI/magellan/internal/util" "github.com/Cray-HPE/hms-xname/xnames" bmclib "github.com/bmc-toolbox/bmclib/v2" @@ -33,7 +33,6 @@ const ( HTTPS_PORT = 443 ) - // NOTE: ...params were getting too long... type QueryParams struct { Host string @@ -121,7 +120,7 @@ func CollectAll(probeStates *[]ScannedResult, l *log.Logger, q *QueryParams) err found := make([]string, 0, len(*probeStates)) done := make(chan struct{}, q.Threads+1) chanProbeState := make(chan ScannedResult, q.Threads+1) - + // collect bmc information asynchronously var offset = 0 var wg sync.WaitGroup @@ -136,7 +135,7 @@ func CollectAll(probeStates *[]ScannedResult, l *log.Logger, q *QueryParams) err } q.Host = ps.Host q.Port = ps.Port - + // generate custom xnames for bmcs node := xnames.Node{ Cabinet: 1000, @@ -158,13 +157,13 @@ func CollectAll(probeStates *[]ScannedResult, l *log.Logger, q *QueryParams) err // data to be sent to smd data := map[string]any{ - "ID": fmt.Sprintf("%v", node.String()[:len(node.String())-2]), - "Type": "", - "Name": "", - "FQDN": ps.Host, - "User": q.User, - "Password": q.Pass, - "MACRequired": true, + "ID": fmt.Sprintf("%v", node.String()[:len(node.String())-2]), + "Type": "", + "Name": "", + "FQDN": ps.Host, + "User": q.User, + "Password": q.Pass, + "MACRequired": true, "RediscoverOnUpdate": false, } @@ -220,7 +219,7 @@ func CollectAll(probeStates *[]ScannedResult, l *log.Logger, q *QueryParams) err } // write JSON data to file - err = os.WriteFile(path.Clean(outputPath + "/" + q.Host + ".json"), body, os.ModePerm) + err = os.WriteFile(path.Clean(outputPath+"/"+q.Host+".json"), body, os.ModePerm) if err != nil { l.Log.Errorf("could not write data to file: %v", err) } @@ -319,7 +318,6 @@ func CollectInventory(client *bmclib.Client, q *QueryParams) ([]byte, error) { return nil, fmt.Errorf("could not get inventory: %v", err) } - // retrieve inventory data data := map[string]any{"Inventory": inventory} b, err := json.MarshalIndent(data, "", " ") @@ -379,7 +377,7 @@ func CollectUsers(client *bmclib.Client, q *QueryParams) ([]byte, error) { } // retrieve inventory data - data := map[string]any {"Users": users} + data := map[string]any{"Users": users} b, err := json.MarshalIndent(data, "", " ") if err != nil { ctxCancel() @@ -407,13 +405,13 @@ func CollectEthernetInterfaces(c *gofish.APIClient, q *QueryParams, systemID str var interfaces []*redfish.EthernetInterface for _, system := range systems { - i, err := redfish.ListReferencedEthernetInterfaces(c, "/redfish/v1/Systems/" + system.ID + "/EthernetInterfaces/") + i, err := redfish.ListReferencedEthernetInterfaces(c, "/redfish/v1/Systems/"+system.ID+"/EthernetInterfaces/") if err != nil { continue } interfaces = append(interfaces, i...) } - + if len(interfaces) <= 0 { return nil, fmt.Errorf("could not get ethernet interfaces: %v", err) } @@ -442,7 +440,7 @@ func CollectChassis(c *gofish.APIClient, q *QueryParams) ([]byte, error) { return b, nil } -func CollectStorage(c *gofish.APIClient, q *QueryParams) ([]byte, error) { +func CollectStorage(c *gofish.APIClient, q *QueryParams) ([]byte, error) { systems, err := c.Service.StorageSystems() if err != nil { return nil, fmt.Errorf("could not query storage systems (%v:%v): %v", q.Host, q.Port, err) @@ -455,7 +453,7 @@ func CollectStorage(c *gofish.APIClient, q *QueryParams) ([]byte, error) { data := map[string]any{ "Storage": map[string]any{ - "Systems": systems, + "Systems": systems, "Services": services, }, } @@ -483,7 +481,7 @@ func CollectSystems(c *gofish.APIClient, q *QueryParams) ([]byte, error) { var i map[string]any json.Unmarshal(interfaces, &i) temp = append(temp, map[string]any{ - "Data": system, + "Data": system, "EthernetInterfaces": i["EthernetInterfaces"], }) } @@ -503,7 +501,7 @@ func CollectRegisteries(c *gofish.APIClient, q *QueryParams) ([]byte, error) { return nil, fmt.Errorf("could not query storage systems (%v:%v): %v", q.Host, q.Port, err) } - data := map[string]any{"Registries": registries } + data := map[string]any{"Registries": registries} b, err := json.MarshalIndent(data, "", " ") if err != nil { return nil, fmt.Errorf("could not marshal JSON: %v", err) @@ -543,7 +541,7 @@ func CollectProcessors(q *QueryParams) ([]byte, error) { } } - data := map[string]any{"Processors": procs } + data := map[string]any{"Processors": procs} b, err := json.MarshalIndent(data, "", " ") if err != nil { return nil, fmt.Errorf("could not marshal JSON: %v", err) @@ -563,7 +561,7 @@ func connectGofish(q *QueryParams) (*gofish.APIClient, error) { c.Service.ProtocolFeaturesSupported = gofish.ProtocolFeaturesSupported{ ExpandQuery: gofish.Expand{ ExpandAll: true, - Links: true, + Links: true, }, } } diff --git a/internal/db/sqlite/sqlite.go b/internal/db/sqlite/sqlite.go index 2e4211e..73f0376 100644 --- a/internal/db/sqlite/sqlite.go +++ b/internal/db/sqlite/sqlite.go @@ -3,7 +3,7 @@ package sqlite import ( "fmt" - magellan "github.com/OpenChami/magellan/internal" + magellan "github.com/OpenCHAMI/magellan/internal" "github.com/jmoiron/sqlx" ) diff --git a/internal/scan.go b/internal/scan.go index ca2729e..68e8f4f 100644 --- a/internal/scan.go +++ b/internal/scan.go @@ -8,7 +8,7 @@ import ( "sync" "time" - "github.com/OpenChami/magellan/internal/util" + "github.com/OpenCHAMI/magellan/internal/util" ) type ScannedResult struct { @@ -51,7 +51,6 @@ func rawConnect(host string, ports []int, timeout int, keepOpenOnly bool) []Scan return results } - func GenerateHosts(subnet string, subnetMask *net.IP) []string { if subnet == "" || subnetMask == nil { return nil @@ -68,7 +67,7 @@ func GenerateHosts(subnet string, subnetMask *net.IP) []string { subnetIp = ip if network != nil { t := net.IP(network.Mask) - subnetMask = &t + subnetMask = &t } } @@ -82,7 +81,7 @@ func generateHosts(ip *net.IP, mask *net.IPMask) []string { // get all IP addresses in network ones, _ := mask.Size() hosts := []string{} - end := int(math.Pow(2, float64((32-ones))))-1 + end := int(math.Pow(2, float64((32-ones)))) - 1 for i := 0; i < end; i++ { // ip[3] = byte(i) ip = util.GetNextIP(ip, 1) diff --git a/internal/update.go b/internal/update.go index 3b352ec..ce5c544 100644 --- a/internal/update.go +++ b/internal/update.go @@ -10,30 +10,29 @@ import ( "strings" "time" - "github.com/OpenChami/magellan/internal/log" - "github.com/OpenChami/magellan/internal/util" + "github.com/OpenCHAMI/magellan/internal/log" + "github.com/OpenCHAMI/magellan/internal/util" bmclib "github.com/bmc-toolbox/bmclib/v2" "github.com/bmc-toolbox/bmclib/v2/constants" bmclibErrs "github.com/bmc-toolbox/bmclib/v2/errors" "github.com/sirupsen/logrus" ) - type UpdateParams struct { QueryParams - FirmwarePath string - FirmwareVersion string - Component string + FirmwarePath string + FirmwareVersion string + Component string TransferProtocol string } -// NOTE: Does not work since OpenBMC, whic bmclib uses underneath, does not +// NOTE: Does not work since OpenBMC, whic bmclib uses underneath, does not // support multipart updates. See issue: https://github.com/bmc-toolbox/bmclib/issues/341 func UpdateFirmware(client *bmclib.Client, l *log.Logger, q *UpdateParams) error { if q.Component == "" { return fmt.Errorf("component is required") } - + // open BMC session and update driver registry ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*time.Duration(q.Timeout)) client.Registry.FilterForCompatible(ctx) @@ -121,20 +120,20 @@ func UpdateFirmware(client *bmclib.Client, l *log.Logger, q *UpdateParams) error time.Sleep(2 * time.Second) } - + return nil } func UpdateFirmwareRemote(q *UpdateParams) error { url := baseRedfishUrl(&q.QueryParams) + "/redfish/v1/UpdateService/Actions/SimpleUpdate" - headers := map[string]string { - "Content-Type": "application/json", + headers := map[string]string{ + "Content-Type": "application/json", "cache-control": "no-cache", } b := map[string]any{ - "UpdateComponent": q.Component, // BMC, BIOS + "UpdateComponent": q.Component, // BMC, BIOS "TransferProtocol": q.TransferProtocol, - "ImageURI": q.FirmwarePath, + "ImageURI": q.FirmwarePath, } data, err := json.Marshal(b) if err != nil { @@ -184,12 +183,10 @@ func GetUpdateStatus(q *UpdateParams) error { // return fmt.Errorf("could not read file: %v", err) // } - - // switch q.TransferProtocol { // case "HTTP": // default: // return fmt.Errorf("transfer protocol not supported") // } // return nil -// } \ No newline at end of file +// } diff --git a/main.go b/main.go index 6f5195a..ebe2d95 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/OpenChami/magellan/cmd" + "github.com/OpenCHAMI/magellan/cmd" ) func main() {