From 9754922c721439cf3db55a6da8d4f48a50a1193e Mon Sep 17 00:00:00 2001 From: Mark Laing Date: Fri, 7 Jul 2023 12:07:35 +0100 Subject: [PATCH 1/9] api: Fixes lint errors. Signed-off-by: Mark Laing --- microcloud/api/services.go | 6 +++--- microcloud/api/services_proxy.go | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/microcloud/api/services.go b/microcloud/api/services.go index 03b2c651a..67b7d957d 100644 --- a/microcloud/api/services.go +++ b/microcloud/api/services.go @@ -19,7 +19,7 @@ import ( type endpointHandler func(*state.State, *http.Request) response.Response // authHandler ensures a request has been authenticated with the mDNS broadcast secret. -func authHandler(sh *service.ServiceHandler, f endpointHandler) endpointHandler { +func authHandler(sh *service.Handler, f endpointHandler) endpointHandler { return func(s *state.State, r *http.Request) response.Response { if r.RemoteAddr == "@" { logger.Debug("Allowing unauthenticated request through unix socket") @@ -45,7 +45,7 @@ func authHandler(sh *service.ServiceHandler, f endpointHandler) endpointHandler } // ServicesCmd represents the /1.0/services API on MicroCloud. -var ServicesCmd = func(sh *service.ServiceHandler) rest.Endpoint { +var ServicesCmd = func(sh *service.Handler) rest.Endpoint { return rest.Endpoint{ AllowedBeforeInit: true, Name: "services", @@ -78,7 +78,7 @@ func servicesPut(s *state.State, r *http.Request) response.Response { addr = req.Address } - sh, err := service.NewServiceHandler(s.Name(), addr, s.OS.StateDir, false, false, services...) + sh, err := service.NewHandler(s.Name(), addr, s.OS.StateDir, false, false, services...) if err != nil { return response.SmartError(err) } diff --git a/microcloud/api/services_proxy.go b/microcloud/api/services_proxy.go index def2ab97e..d24febabe 100644 --- a/microcloud/api/services_proxy.go +++ b/microcloud/api/services_proxy.go @@ -17,17 +17,17 @@ import ( ) // LXDProxy proxies all requests from MicroCloud to LXD. -func LXDProxy(sh *service.ServiceHandler) rest.Endpoint { +func LXDProxy(sh *service.Handler) rest.Endpoint { return proxy(sh, "lxd", "services/lxd/{rest:.*}", lxdHandler) } // CephProxy proxies all requests from MicroCloud to MicroCeph. -func CephProxy(sh *service.ServiceHandler) rest.Endpoint { +func CephProxy(sh *service.Handler) rest.Endpoint { return proxy(sh, "microceph", "services/microceph/{rest:.*}", microHandler("microceph", MicroCephDir)) } // OVNProxy proxies all requests from MicroCloud to MicroOVN. -func OVNProxy(sh *service.ServiceHandler) rest.Endpoint { +func OVNProxy(sh *service.Handler) rest.Endpoint { return proxy(sh, "microovn", "services/microovn/{rest:.*}", microHandler("microovn", MicroOVNDir)) } @@ -41,7 +41,7 @@ const MicroCephDir = "/var/snap/microceph/common/state" const MicroOVNDir = "/var/snap/microovn/common/state" // proxy returns a proxy endpoint with the given handler and access applied to all REST methods. -func proxy(sh *service.ServiceHandler, name, path string, handler endpointHandler) rest.Endpoint { +func proxy(sh *service.Handler, name, path string, handler endpointHandler) rest.Endpoint { return rest.Endpoint{ AllowedBeforeInit: true, Name: name, From 629087dea93dcba3a23a58f79cbb28d8cfd6f59d Mon Sep 17 00:00:00 2001 From: Mark Laing Date: Fri, 7 Jul 2023 12:07:49 +0100 Subject: [PATCH 2/9] cmd: Fixes lint errors. Signed-off-by: Mark Laing --- microcloud/cmd/microcloud/add.go | 2 +- microcloud/cmd/microcloud/ask.go | 6 +++--- microcloud/cmd/microcloud/main_init.go | 13 ++++++------- microcloud/cmd/microcloud/selection_table.go | 2 +- microcloud/cmd/microcloud/sql.go | 2 +- microcloud/cmd/microcloudd/main.go | 8 ++++---- 6 files changed, 16 insertions(+), 17 deletions(-) diff --git a/microcloud/cmd/microcloud/add.go b/microcloud/cmd/microcloud/add.go index 2f5e1dece..17ef96e9e 100644 --- a/microcloud/cmd/microcloud/add.go +++ b/microcloud/cmd/microcloud/add.go @@ -67,7 +67,7 @@ func (c *cmdAdd) Run(cmd *cobra.Command, args []string) error { return err } - s, err := service.NewServiceHandler(status.Name, addr, c.common.FlagMicroCloudDir, c.common.FlagLogDebug, c.common.FlagLogVerbose, services...) + s, err := service.NewHandler(status.Name, addr, c.common.FlagMicroCloudDir, c.common.FlagLogDebug, c.common.FlagLogVerbose, services...) if err != nil { return err } diff --git a/microcloud/cmd/microcloud/ask.go b/microcloud/cmd/microcloud/ask.go index d1203d89d..f60230409 100644 --- a/microcloud/cmd/microcloud/ask.go +++ b/microcloud/cmd/microcloud/ask.go @@ -44,7 +44,7 @@ func askRetry(question string, autoSetup bool, f func() error) { func askMissingServices(services []types.ServiceType, stateDirs map[types.ServiceType]string, autoSetup bool) ([]types.ServiceType, error) { missingServices := []string{} for serviceType, stateDir := range stateDirs { - if service.ServiceExists(serviceType, stateDir) { + if service.Exists(serviceType, stateDir) { services = append(services, serviceType) } else { missingServices = append(missingServices, string(serviceType)) @@ -140,7 +140,7 @@ func askAddress(autoSetup bool, listenAddr string) (string, *net.IPNet, error) { return listenAddr, subnet, nil } -func askDisks(sh *service.ServiceHandler, peers map[string]mdns.ServerInfo, bootstrap bool, autoSetup bool, wipeAllDisks bool) (map[string][]lxdAPI.ClusterMemberConfigKey, map[string][]cephTypes.DisksPost, error) { +func askDisks(sh *service.Handler, peers map[string]mdns.ServerInfo, bootstrap bool, autoSetup bool, wipeAllDisks bool) (map[string][]lxdAPI.ClusterMemberConfigKey, map[string][]cephTypes.DisksPost, error) { if bootstrap { // Add the local system to the list of peers so we can select disks. peers[sh.Name] = mdns.ServerInfo{Name: sh.Name} @@ -481,7 +481,7 @@ func askRemotePool(peerDisks map[string][]lxdAPI.ResourcesStorageDisk, autoSetup return nil, fmt.Errorf("Unable to add remote storage pool: Each peer (minimum 3) must have allocated disks") } -func askNetwork(sh *service.ServiceHandler, peers map[string]mdns.ServerInfo, lxdConfig map[string][]api.ClusterMemberConfigKey, bootstrap bool, autoSetup bool) (map[string]string, map[string]string, error) { +func askNetwork(sh *service.Handler, peers map[string]mdns.ServerInfo, lxdConfig map[string][]api.ClusterMemberConfigKey, bootstrap bool, autoSetup bool) (map[string]string, map[string]string, error) { // Automatic setup gets a basic fan setup. if autoSetup { return nil, nil, nil diff --git a/microcloud/cmd/microcloud/main_init.go b/microcloud/cmd/microcloud/main_init.go index b6872f30f..d07a05b94 100644 --- a/microcloud/cmd/microcloud/main_init.go +++ b/microcloud/cmd/microcloud/main_init.go @@ -61,7 +61,7 @@ func (c *cmdInit) Run(cmd *cobra.Command, args []string) error { return fmt.Errorf("Failed to retrieve system hostname: %w", err) } - if !c.flagAutoSetup { + if !c.flagAutoSetup { //nolint:staticcheck // FIXME: MicroCeph does not currently support non-hostname cluster names. // name, err = cli.AskString(fmt.Sprintf("Specify a name for this system [default=%s]: ", name), name, nil) // if err != nil { @@ -80,7 +80,7 @@ func (c *cmdInit) Run(cmd *cobra.Command, args []string) error { return err } - s, err := service.NewServiceHandler(name, addr, c.common.FlagMicroCloudDir, c.common.FlagLogDebug, c.common.FlagLogVerbose, services...) + s, err := service.NewHandler(name, addr, c.common.FlagMicroCloudDir, c.common.FlagLogDebug, c.common.FlagLogVerbose, services...) if err != nil { return err } @@ -144,7 +144,7 @@ func (c *cmdInit) Run(cmd *cobra.Command, args []string) error { return nil } -func lookupPeers(s *service.ServiceHandler, autoSetup bool, subnet *net.IPNet) (map[string]mdns.ServerInfo, error) { +func lookupPeers(s *service.Handler, autoSetup bool, subnet *net.IPNet) (map[string]mdns.ServerInfo, error) { header := []string{"NAME", "IFACE", "ADDR"} var table *SelectableTable var answers []string @@ -161,7 +161,6 @@ func lookupPeers(s *service.ServiceHandler, autoSetup bool, subnet *net.IPNet) ( answers, err = table.GetSelections() selectionCh <- err - return }() } @@ -264,7 +263,7 @@ func lookupPeers(s *service.ServiceHandler, autoSetup bool, subnet *net.IPNet) ( return selectedPeers, nil } -func AddPeers(sh *service.ServiceHandler, peers map[string]mdns.ServerInfo, localDisks map[string][]lxdAPI.ClusterMemberConfigKey, cephDisks map[string][]cephTypes.DisksPost) error { +func AddPeers(sh *service.Handler, peers map[string]mdns.ServerInfo, localDisks map[string][]lxdAPI.ClusterMemberConfigKey, cephDisks map[string][]cephTypes.DisksPost) error { joinConfig := make(map[string]types.ServicesPut, len(peers)) secrets := make(map[string]string, len(peers)) for peer, info := range peers { @@ -370,7 +369,7 @@ func AddPeers(sh *service.ServiceHandler, peers map[string]mdns.ServerInfo, loca // waitForCluster will loop until the timeout has passed, or all cluster members for all services have reported that // their join process is complete. -func waitForCluster(sh *service.ServiceHandler, secrets map[string]string, peers map[string]types.ServicesPut) error { +func waitForCluster(sh *service.Handler, secrets map[string]string, peers map[string]types.ServicesPut) error { cloud := sh.Services[types.MicroCloud].(*service.CloudService) joinedChan := cloud.RequestJoin(context.Background(), secrets, peers) timeAfter := time.After(5 * time.Minute) @@ -411,7 +410,7 @@ func waitForCluster(sh *service.ServiceHandler, secrets map[string]string, peers } } -func postClusterSetup(bootstrap bool, sh *service.ServiceHandler, peers map[string]mdns.ServerInfo, lxdDisks map[string][]lxdAPI.ClusterMemberConfigKey, cephDisks map[string][]cephTypes.DisksPost, uplinkNetworks map[string]string, networkConfig map[string]string) error { +func postClusterSetup(bootstrap bool, sh *service.Handler, peers map[string]mdns.ServerInfo, lxdDisks map[string][]lxdAPI.ClusterMemberConfigKey, cephDisks map[string][]cephTypes.DisksPost, uplinkNetworks map[string]string, networkConfig map[string]string) error { cephTargets := map[string]string{} for target := range cephDisks { cephTargets[target] = peers[target].AuthSecret diff --git a/microcloud/cmd/microcloud/selection_table.go b/microcloud/cmd/microcloud/selection_table.go index b8f8c8b10..efd522b40 100644 --- a/microcloud/cmd/microcloud/selection_table.go +++ b/microcloud/cmd/microcloud/selection_table.go @@ -233,6 +233,7 @@ func (t *SelectableTable) prepareTemplate() { return line } + core.TemplateFuncsNoColor["add"] = core.TemplateFuncsWithColor["add"] core.TemplateFuncsNoColor["scroll_hint_bot"] = core.TemplateFuncsWithColor["scroll_hint_bot"] core.TemplateFuncsNoColor["scroll_hint_top"] = core.TemplateFuncsWithColor["scroll_hint_top"] @@ -253,7 +254,6 @@ Up/down to move; right to select all; left to select none.`, go func() { err := survey.AskOne(t.prompt, &t.answers, survey.WithKeepFilter(true)) if err != nil && err.Error() != "please provide options to select from" { - t.askChan <- fmt.Errorf("Failed to confirm selection: %w", err) return } diff --git a/microcloud/cmd/microcloud/sql.go b/microcloud/cmd/microcloud/sql.go index d5114c6b6..5fc10f519 100644 --- a/microcloud/cmd/microcloud/sql.go +++ b/microcloud/cmd/microcloud/sql.go @@ -49,7 +49,7 @@ func (c *cmdSQL) Run(cmd *cobra.Command, args []string) error { } if dump != "" { - fmt.Printf(dump) + fmt.Print(dump) return nil } diff --git a/microcloud/cmd/microcloudd/main.go b/microcloud/cmd/microcloudd/main.go index 0de37003d..5657a0cce 100644 --- a/microcloud/cmd/microcloudd/main.go +++ b/microcloud/cmd/microcloudd/main.go @@ -70,14 +70,14 @@ func (c *cmdDaemon) Run(cmd *cobra.Command, args []string) error { } for serviceType, stateDir := range optionalServices { - if service.ServiceExists(serviceType, stateDir) { + if service.Exists(serviceType, stateDir) { services = append(services, serviceType) } else { logger.Infof("Skipping %s service, could not detect state directory", serviceType) } } - s, err := service.NewServiceHandler(name, addr, c.flagMicroCloudDir, c.global.flagLogDebug, c.global.flagLogVerbose, services...) + s, err := service.NewHandler(name, addr, c.flagMicroCloudDir, c.global.flagLogDebug, c.global.flagLogVerbose, services...) if err != nil { return err } @@ -98,8 +98,8 @@ func (c *cmdDaemon) Run(cmd *cobra.Command, args []string) error { continue } - if service.ServiceExists(serviceName, stateDir) { - newService, err := service.NewServiceHandler(name, addr, c.flagMicroCloudDir, false, false, serviceName) + if service.Exists(serviceName, stateDir) { + newService, err := service.NewHandler(name, addr, c.flagMicroCloudDir, false, false, serviceName) if err != nil { logger.Error("Failed to create servie handler for service", logger.Ctx{"service": serviceName, "error": err}) break From 2163f9d1d565a8b9bd1668399e4a788730f2e44a Mon Sep 17 00:00:00 2001 From: Mark Laing Date: Fri, 7 Jul 2023 12:08:01 +0100 Subject: [PATCH 3/9] mdns: Fixes lint errors. Signed-off-by: Mark Laing --- microcloud/mdns/lookup.go | 6 ++---- microcloud/mdns/mdns.go | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/microcloud/mdns/lookup.go b/microcloud/mdns/lookup.go index 01908c0bb..3e8657150 100644 --- a/microcloud/mdns/lookup.go +++ b/microcloud/mdns/lookup.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "io" "log" "net" "strconv" @@ -40,9 +39,7 @@ func (s ServerInfo) LookupKey() string { } // forwardingWriter forwards the mdns log message to LXD's logger package. -type forwardingWriter struct { - w io.Writer -} +type forwardingWriter struct{} func (f forwardingWriter) Write(p []byte) (int, error) { logMsg := string(p) @@ -127,6 +124,7 @@ func LookupPeers(ctx context.Context, version string, localPeer string) (map[str return peers, nil } +// Lookup searches for the given service name over mdns. func Lookup(ctx context.Context, service string, size int) ([]*mdns.ServiceEntry, error) { log.SetOutput(forwardingWriter{}) ctx, cancel := context.WithCancel(ctx) diff --git a/microcloud/mdns/mdns.go b/microcloud/mdns/mdns.go index 5770da7eb..69d219f88 100644 --- a/microcloud/mdns/mdns.go +++ b/microcloud/mdns/mdns.go @@ -10,12 +10,13 @@ import ( // ClusterService is the service name used for broadcasting willingness to join a cluster. const ClusterService = "_microcloud" -// serviceSize is the maximum number of simultaneous broadcasts of the same mDNS service. +// ServiceSize is the maximum number of simultaneous broadcasts of the same mDNS service. const ServiceSize = 10 // clusterSize is the maximum number of cluster members we can find. const clusterSize = 1000 +// NewBroadcast returns a running mdns.Server which broadcasts the service at the given name and address. func NewBroadcast(name string, addr string, port int, service string, txt []byte) (*mdns.Server, error) { var sendTXT []string if txt != nil { From e8f0778797bcbeed1bcc06b22006cb12bfd5cf88 Mon Sep 17 00:00:00 2001 From: Mark Laing Date: Fri, 7 Jul 2023 12:08:13 +0100 Subject: [PATCH 4/9] service: Fixes lint errors. Signed-off-by: Mark Laing --- microcloud/service/lxd.go | 4 +++- microcloud/service/lxd_join.go | 1 + microcloud/service/microcloud.go | 2 +- microcloud/service/microovn.go | 2 +- microcloud/service/service_handler.go | 27 +++++++++++---------------- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/microcloud/service/lxd.go b/microcloud/service/lxd.go index e01bca35c..eabd39487 100644 --- a/microcloud/service/lxd.go +++ b/microcloud/service/lxd.go @@ -235,7 +235,7 @@ func (s LXDService) Port() int { return s.port } -// AddLocalPools adds local zfs storage pools on the target peers, with the given source disks. +// AddLocalPool adds local zfs storage pool on the target peers, with the given source disks. func (s *LXDService) AddLocalPool(source string, wipe bool) error { c, err := s.client("") if err != nil { @@ -363,6 +363,7 @@ func (s *LXDService) GetResources(target string, address string, secret string) return client.GetServerResources() } +// GetUplinkInterfaces returns a map of peer name to slice of api.Network that may be used with OVN. func (s LXDService) GetUplinkInterfaces(bootstrap bool, peers map[string]mdns.ServerInfo) (map[string][]api.Network, error) { clients := map[string]lxd.InstanceServer{} networks := map[string][]api.Network{} @@ -446,6 +447,7 @@ func (s LXDService) GetUplinkInterfaces(bootstrap bool, peers map[string]mdns.Se return candidates, nil } +// SetupNetwork configures LXD to use the OVN network uplink or to use a fan overlay if this is not available. func (s LXDService) SetupNetwork(uplinkNetworks map[string]string, networkConfig map[string]string) error { client, err := s.client("") if err != nil { diff --git a/microcloud/service/lxd_join.go b/microcloud/service/lxd_join.go index 84aedcca6..a8f1a3b72 100644 --- a/microcloud/service/lxd_join.go +++ b/microcloud/service/lxd_join.go @@ -16,6 +16,7 @@ func (s *LXDService) configFromToken(token string) (*api.ClusterPut, error) { if err != nil { return nil, fmt.Errorf("Invalid cluster join token: %w", err) } + config := &api.ClusterPut{ Cluster: api.Cluster{ServerName: s.name, Enabled: true}, ServerAddress: util.CanonicalNetworkAddress(s.address, s.port), diff --git a/microcloud/service/microcloud.go b/microcloud/service/microcloud.go index 739ff223b..63f6e02a9 100644 --- a/microcloud/service/microcloud.go +++ b/microcloud/service/microcloud.go @@ -60,7 +60,7 @@ func NewCloudService(ctx context.Context, name string, addr string, dir string, } // StartCloud launches the MicroCloud daemon with the appropriate hooks. -func (s *CloudService) StartCloud(service *ServiceHandler, endpoints []rest.Endpoint) error { +func (s *CloudService) StartCloud(service *Handler, endpoints []rest.Endpoint) error { return s.client.Start(endpoints, nil, &config.Hooks{ OnBootstrap: func(s *state.State) error { return service.StopBroadcast() }, PostJoin: func(s *state.State) error { return service.StopBroadcast() }, diff --git a/microcloud/service/microovn.go b/microcloud/service/microovn.go index be401cbce..658fbe664 100644 --- a/microcloud/service/microovn.go +++ b/microcloud/service/microovn.go @@ -47,7 +47,7 @@ func NewOVNService(ctx context.Context, name string, addr string, cloudDir strin }, nil } -// client returns a client to the OVN unix socket. +// Client returns a client to the OVN unix socket. func (s OVNService) Client() (*client.Client, error) { return s.m.LocalClient() } diff --git a/microcloud/service/service_handler.go b/microcloud/service/service_handler.go index 68120a8d8..ed8c35bd6 100644 --- a/microcloud/service/service_handler.go +++ b/microcloud/service/service_handler.go @@ -31,8 +31,8 @@ const ( CloudPort int = 9443 ) -// ServiceHandler holds a set of services and an mdns server for communication between them. -type ServiceHandler struct { +// Handler holds a set of services and an mdns server for communication between them. +type Handler struct { servers []*mdns.Server Services map[types.ServiceType]Service @@ -43,8 +43,8 @@ type ServiceHandler struct { AuthSecret string } -// NewServiceHandler creates a new ServiceHandler with a client for each of the given services. -func NewServiceHandler(name string, addr string, stateDir string, debug bool, verbose bool, services ...types.ServiceType) (*ServiceHandler, error) { +// NewHandler creates a new Handler with a client for each of the given services. +func NewHandler(name string, addr string, stateDir string, debug bool, verbose bool, services ...types.ServiceType) (*Handler, error) { servicesMap := make(map[types.ServiceType]Service, len(services)) for _, serviceType := range services { var service Service @@ -52,16 +52,12 @@ func NewServiceHandler(name string, addr string, stateDir string, debug bool, ve switch serviceType { case types.MicroCloud: service, err = NewCloudService(context.Background(), name, addr, stateDir, verbose, debug) - break case types.MicroCeph: service, err = NewCephService(context.Background(), name, addr, stateDir) - break case types.MicroOVN: service, err = NewOVNService(context.Background(), name, addr, stateDir) - break case types.LXD: service, err = NewLXDService(context.Background(), name, addr, stateDir) - break } if err != nil { @@ -71,7 +67,7 @@ func NewServiceHandler(name string, addr string, stateDir string, debug bool, ve servicesMap[serviceType] = service } - return &ServiceHandler{ + return &Handler{ servers: []*mdns.Server{}, Services: servicesMap, Name: name, @@ -82,7 +78,7 @@ func NewServiceHandler(name string, addr string, stateDir string, debug bool, ve // Start is run after the MicroCloud daemon has started. It will periodically check for join token broadcasts, and if // found, will join all known services. -func (s *ServiceHandler) Start(state *state.State) error { +func (s *Handler) Start(state *state.State) error { // If we are already initialized, there's nothing to do. if state.Database.IsOpen() { return nil @@ -103,7 +99,7 @@ func (s *ServiceHandler) Start(state *state.State) error { } // Broadcast broadcasts service information over mDNS. -func (s *ServiceHandler) Broadcast() error { +func (s *Handler) Broadcast() error { services := make([]types.ServiceType, 0, len(s.Services)) for service := range s.Services { services = append(services, service) @@ -157,11 +153,10 @@ func (s *ServiceHandler) Broadcast() error { } return nil - } // StopBroadcast stops the mDNS broadcast and token lookup, as we are initiating a new cluster. -func (s *ServiceHandler) StopBroadcast() error { +func (s *Handler) StopBroadcast() error { for i, server := range s.servers { service := fmt.Sprintf("%s_%d", cloudMDNS.ClusterService, i) err := server.Shutdown() @@ -175,7 +170,7 @@ func (s *ServiceHandler) StopBroadcast() error { // RunConcurrent runs the given hook concurrently across all services. // If microCloudFirst is true, then MicroCloud will have its hook run before the others. -func (s *ServiceHandler) RunConcurrent(microCloudFirst bool, lxdLast bool, f func(s Service) error) error { +func (s *Handler) RunConcurrent(microCloudFirst bool, lxdLast bool, f func(s Service) error) error { errors := make([]error, 0, len(s.Services)) mut := sync.Mutex{} wg := sync.WaitGroup{} @@ -243,8 +238,8 @@ func (s *ServiceHandler) RunConcurrent(microCloudFirst bool, lxdLast bool, f fun return nil } -// ServiceExists returns true if we can stat the unix socket in the state directory of the given service. -func ServiceExists(service types.ServiceType, stateDir string) bool { +// Exists returns true if we can stat the unix socket in the state directory of the given service. +func Exists(service types.ServiceType, stateDir string) bool { socketPath := filepath.Join(stateDir, "control.socket") if service == types.LXD { socketPath = filepath.Join(stateDir, "unix.socket") From 85148e611721046da7236da3d523570c9c038b63 Mon Sep 17 00:00:00 2001 From: Mark Laing Date: Fri, 7 Jul 2023 12:08:36 +0100 Subject: [PATCH 5/9] test/lint: Adds lint scripts. Signed-off-by: Mark Laing --- microcloud/test/lint/negated-is-bool.sh | 9 +++++++ microcloud/test/lint/newline-after-block.sh | 27 +++++++++++++++++++ .../test/lint/no-oneline-assign-and-test.sh | 6 +++++ microcloud/test/lint/no-short-form-imports.sh | 9 +++++++ 4 files changed, 51 insertions(+) create mode 100755 microcloud/test/lint/negated-is-bool.sh create mode 100755 microcloud/test/lint/newline-after-block.sh create mode 100755 microcloud/test/lint/no-oneline-assign-and-test.sh create mode 100755 microcloud/test/lint/no-short-form-imports.sh diff --git a/microcloud/test/lint/negated-is-bool.sh b/microcloud/test/lint/negated-is-bool.sh new file mode 100755 index 000000000..f70d27e10 --- /dev/null +++ b/microcloud/test/lint/negated-is-bool.sh @@ -0,0 +1,9 @@ +#!/bin/sh -eu + +echo "Checking usage of negated shared.Is(True|False)*() functions..." + +OUT=$(git grep --untracked -P '!(shared\.)?Is(True|False).*\(' '*.go' || true) +if [ -n "${OUT}" ]; then + echo "ERROR: negated shared.Is(True|False)*() function in script: ${OUT}" + exit 1 +fi diff --git a/microcloud/test/lint/newline-after-block.sh b/microcloud/test/lint/newline-after-block.sh new file mode 100755 index 000000000..a5b150733 --- /dev/null +++ b/microcloud/test/lint/newline-after-block.sh @@ -0,0 +1,27 @@ +#!/bin/sh -eu + +echo "Checking that functional blocks are followed by newlines..." + +# Check all .go files except the protobuf bindings (.pb.go) +files=$(git ls-files --cached --modified --others '*.go' ':!:*.pb.go') + +exit_code=0 +for file in $files +do + # This oneliner has a few steps: + # 1. sed: + # a. Check for lines that contain a single closing brace (plus whitespace). + # b. Move the pattern space window forward to the next line. + # c. Match lines that start with a word character. This allows for a closing brace on subsequent lines. + # d. Print the line number. + # 2. xargs: Print the filename next to the line number of the matches (piped). + # 3. If there were no matches, the file name without the line number is printed, use grep to filter it out. + # 4. Replace the space with a colon to make a clickable link. + RESULT=$(sed -n -e '/^\s*}\s*$/{n;/^\s*\w/{;=}}' "$file" | xargs -L 1 echo "$file" | grep -v '\.go$' | sed 's/ /:/g') + if [ -n "${RESULT}" ]; then + echo "${RESULT}" + exit_code=1 + fi +done + +exit $exit_code diff --git a/microcloud/test/lint/no-oneline-assign-and-test.sh b/microcloud/test/lint/no-oneline-assign-and-test.sh new file mode 100755 index 000000000..dfb0ace4d --- /dev/null +++ b/microcloud/test/lint/no-oneline-assign-and-test.sh @@ -0,0 +1,6 @@ +#!/bin/sh -eu + +echo "Checking for oneline assign & test..." + +# Recursively grep go files for if statements that contain assignments. +! git grep --untracked -P -n '^\s+if.*:=.*;.*{\s*$' -- '*.go' diff --git a/microcloud/test/lint/no-short-form-imports.sh b/microcloud/test/lint/no-short-form-imports.sh new file mode 100755 index 000000000..f7d231c45 --- /dev/null +++ b/microcloud/test/lint/no-short-form-imports.sh @@ -0,0 +1,9 @@ +#!/bin/sh -eu + +echo "Checking for short form imports..." + +OUT=$(git grep --untracked -n -P '^\s*import\s+"' '*.go' | grep -v ':import "C"$' || true) +if [ -n "${OUT}" ]; then + echo "ERROR: found short form imports: ${OUT}" + exit 1 +fi From a16c40f48771e69e2cd89220e4ebffdd586e6db6 Mon Sep 17 00:00:00 2001 From: Mark Laing Date: Fri, 7 Jul 2023 12:08:57 +0100 Subject: [PATCH 6/9] golangci: Adds golangci-lint config. Signed-off-by: Mark Laing --- microcloud/.golangci.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 microcloud/.golangci.yml diff --git a/microcloud/.golangci.yml b/microcloud/.golangci.yml new file mode 100644 index 000000000..153ed9881 --- /dev/null +++ b/microcloud/.golangci.yml @@ -0,0 +1,13 @@ +linters: + enable: + - gofmt + - misspell + - godot + - whitespace + - gci +linters-settings: + gci: + sections: + - standard + - default + - prefix(github.com/canonical/microcloud/microcloud) From da716d6f58074ebe1f74b58c1fad0d83ad69d6f3 Mon Sep 17 00:00:00 2001 From: Mark Laing Date: Fri, 7 Jul 2023 12:09:09 +0100 Subject: [PATCH 7/9] revive: Adds revive config. Signed-off-by: Mark Laing --- microcloud/revive.toml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 microcloud/revive.toml diff --git a/microcloud/revive.toml b/microcloud/revive.toml new file mode 100644 index 000000000..4c142c152 --- /dev/null +++ b/microcloud/revive.toml @@ -0,0 +1,2 @@ +[rule.exported] + Arguments = ["checkPrivateReceivers"] From 9a9bf2d7369788fb0bbec0b519ef64b27e78884a Mon Sep 17 00:00:00 2001 From: Mark Laing Date: Fri, 7 Jul 2023 12:09:37 +0100 Subject: [PATCH 8/9] Makefile: Updates check-static target. Signed-off-by: Mark Laing --- microcloud/Makefile | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/microcloud/Makefile b/microcloud/Makefile index 8e27d68e1..89d152afb 100644 --- a/microcloud/Makefile +++ b/microcloud/Makefile @@ -22,17 +22,14 @@ check-system: .PHONY: check-static check-static: ifeq ($(shell command -v golangci-lint 2> /dev/null),) - go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest -endif -ifeq ($(shell command -v shellcheck 2> /dev/null),) - echo "Please install shellcheck" - exit 1 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $$HOME/go/bin endif ifeq ($(shell command -v revive 2> /dev/null),) go install github.com/mgechev/revive@latest endif golangci-lint run --timeout 5m - revive -set_exit_status ./... + revive -config revive.toml -exclude ./cmd/... -set_exit_status ./... + run-parts --exit-on-error --regex '.sh' test/lint # Update targets. .PHONY: update-gomod From 2d22044c202c5bb79e9347917ff9370ea5d04f45 Mon Sep 17 00:00:00 2001 From: Mark Laing Date: Fri, 7 Jul 2023 12:10:11 +0100 Subject: [PATCH 9/9] workflows: Adds code tests job. Signed-off-by: Mark Laing --- .github/workflows/tests.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f27f4974b..dd6521c9e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,6 +8,32 @@ concurrency: cancel-in-progress: true jobs: + code-tests: + name: Code tests + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install Go + uses: actions/setup-go@v4 + with: + go-version: 1.18.x + + - name: Install dependencies + run: | + sudo add-apt-repository ppa:dqlite/dev -y --no-update + sudo apt-get update + sudo apt-get install --no-install-recommends -y libdqlite-dev pkg-config + + - name: Update gomod + working-directory: microcloud + run: make update-gomod + + - name: Run static analysis + working-directory: microcloud + run: make check-static + system-tests: name: System tests runs-on: ubuntu-22.04