diff --git a/.golangci.yml b/.golangci.yml new file mode 100755 index 0000000..b84ded5 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,202 @@ +# NOTE: This file is populated by the lint-install tool. Local adjustments may be overwritten. +linters-settings: + cyclop: + # NOTE: This is a very high transitional threshold + max-complexity: 37 + package-average: 34.0 + skip-tests: true + + gocognit: + # NOTE: This is a very high transitional threshold + min-complexity: 98 + + dupl: + threshold: 200 + + goconst: + min-len: 4 + min-occurrences: 5 + ignore-tests: true + + gosec: + excludes: + - G107 # Potential HTTP request made with variable url + - G204 # Subprocess launched with function call as argument or cmd arguments + - G404 # Use of weak random number generator (math/rand instead of crypto/rand + + errorlint: + # these are still common in Go: for instance, exit errors. + asserts: false + + exhaustive: + default-signifies-exhaustive: true + + nestif: + min-complexity: 8 + + nolintlint: + require-explanation: true + allow-unused: false + require-specific: true + + revive: + ignore-generated-header: true + severity: warning + rules: + - name: atomic + - name: blank-imports + - name: bool-literal-in-expr + - name: confusing-naming + - name: constant-logical-expr + - name: context-as-argument + - name: context-keys-type + - name: deep-exit + - name: defer + - name: range-val-in-closure + - name: range-val-address + - name: dot-imports + - name: error-naming + - name: error-return + - name: error-strings + - name: errorf + - name: exported + - name: identical-branches + - name: if-return + - name: import-shadowing + - name: increment-decrement + - name: indent-error-flow + - name: indent-error-flow + - name: package-comments + - name: range + - name: receiver-naming + - name: redefines-builtin-id + - name: superfluous-else + - name: struct-tag + - name: time-naming + - name: unexported-naming + - name: unexported-return + - name: unnecessary-stmt + - name: unreachable-code + - name: unused-parameter + - name: var-declaration + - name: var-naming + - name: unconditional-recursion + - name: waitgroup-by-value + + staticcheck: + go: "1.16" + + unused: + go: "1.16" + +output: + sort-results: true + +linters: + disable-all: true + enable: + - asciicheck + - bodyclose + - cyclop + - deadcode + - dogsled + - dupl + - durationcheck + - errcheck + # errname is only available in golangci-lint v1.42.0+ - wait until v1.43 is available to settle + #- errname + - errorlint + - exhaustive + - exportloopref + - forcetypeassert + - gocognit + - goconst + - gocritic + - godot + - gofmt + - gofumpt + - gosec + - goheader + - goimports + - goprintffuncname + - gosimple + - govet + - ifshort + - importas + - ineffassign + - makezero + - misspell + - nakedret + - nestif + - nilerr + - noctx + - nolintlint + - predeclared + # disabling for the initial iteration of the linting tool + #- promlinter + - revive + - rowserrcheck + - sqlclosecheck + - staticcheck + - structcheck + - stylecheck + - thelper + - tparallel + - typecheck + - unconvert + - unparam + - unused + - varcheck + - wastedassign + - whitespace + + # Disabled linters, due to being misaligned with Go practices + # - exhaustivestruct + # - gochecknoglobals + # - gochecknoinits + # - goconst + # - godox + # - goerr113 + # - gomnd + # - lll + # - nlreturn + # - testpackage + # - wsl + # Disabled linters, due to not being relevant to our code base: + # - maligned + # - prealloc "For most programs usage of prealloc will be a premature optimization." + # Disabled linters due to bad error messages or bugs + # - tagliatelle + +issues: + # Excluding configuration per-path, per-linter, per-text and per-source + exclude-rules: + - path: _test\.go + linters: + - gocyclo + - errcheck + - dupl + - gosec + + - path: cmd.* + linters: + - noctx + + - path: main\.go + linters: + - noctx + + - path: cmd.* + text: "deep-exit" + + - path: main\.go + text: "deep-exit" + + # This check is of questionable value + - linters: + - tparallel + text: "call t.Parallel on the top level as well as its subtests" + + # Don't hide lint issues just because there are many of them + max-same-issues: 0 + max-issues-per-linter: 0 diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..924acf6 --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ + +# BEGIN: lint-install ../infrastructure/ +# http://github.com/tinkerbell/lint-install + +GOLINT_VERSION ?= v1.42.0 + + +LINT_OS := $(shell uname) +LINT_ARCH := $(shell uname -m) + +# shellcheck and hadolint lack arm64 native binaries: rely on x86-64 emulation +ifeq ($(LINT_OS),Darwin) + ifeq ($(LINT_ARCH),arm64) + LINT_ARCH=x86_64 + endif +endif + + +GOLINT_CONFIG:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))/.golangci.yml + +lint: out/linters/golangci-lint-$(GOLINT_VERSION)-$(LINT_ARCH) + find . -name go.mod | xargs -n1 dirname | xargs -n1 -I{} sh -c "cd {} && golangci-lint run -c $(GOLINT_CONFIG)" + +out/linters/golangci-lint-$(GOLINT_VERSION)-$(LINT_ARCH): + mkdir -p out/linters + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b out/linters $(GOLINT_VERSION) + mv out/linters/golangci-lint out/linters/golangci-lint-$(GOLINT_VERSION)-$(LINT_ARCH) + +# END: lint-install ../infrastructure/ diff --git a/pulumi/src/assets/main.go b/pulumi/src/assets/main.go index 56802b4..122a09d 100644 --- a/pulumi/src/assets/main.go +++ b/pulumi/src/assets/main.go @@ -6,11 +6,11 @@ import ( "github.com/tinkerbell/infrastructure/src/internal" ) -type AssetsDns struct { +type DNS struct { Cname *ns1.Record } -func CreateAssetsDns(ctx *pulumi.Context, infrastructure internal.Infrastructure) (AssetsDns, error) { +func CreateDNS(ctx *pulumi.Context, infrastructure internal.Infrastructure) (DNS, error) { // This verification record is required for Cloudflare to issue a certificate for this domain _, err := ns1.NewRecord(ctx, "assets-cname-verification", &ns1.RecordArgs{ Zone: pulumi.String(infrastructure.Zone.Zone), @@ -22,9 +22,8 @@ func CreateAssetsDns(ctx *pulumi.Context, infrastructure internal.Infrastructure }, }, }) - if err != nil { - return AssetsDns{}, err + return DNS{}, err } // assets.tinkerbell.org @@ -41,12 +40,11 @@ func CreateAssetsDns(ctx *pulumi.Context, infrastructure internal.Infrastructure }, }, }) - if err != nil { - return AssetsDns{}, err + return DNS{}, err } - return AssetsDns{ + return DNS{ Cname: cname, }, nil } diff --git a/pulumi/src/dns/tinkerbell.org/main.go b/pulumi/src/dns/tinkerbell.org/main.go index 42fe45e..11f2dfa 100644 --- a/pulumi/src/dns/tinkerbell.org/main.go +++ b/pulumi/src/dns/tinkerbell.org/main.go @@ -5,11 +5,10 @@ import ( "github.com/pulumi/pulumi/sdk/v2/go/pulumi" ) -func ManageDns(ctx *pulumi.Context) (ns1.LookupZoneResult, error) { +func ManageDNS(ctx *pulumi.Context) (ns1.LookupZoneResult, error) { zone, err := ns1.LookupZone(ctx, &ns1.LookupZoneArgs{ Zone: "tinkerbell.org", }) - if err != nil { return ns1.LookupZoneResult{}, err } diff --git a/pulumi/src/github-actions/cloud-init.go b/pulumi/src/github-actions/cloud-init.go index 93a4132..fc2f227 100644 --- a/pulumi/src/github-actions/cloud-init.go +++ b/pulumi/src/github-actions/cloud-init.go @@ -7,13 +7,12 @@ import ( ) type MinionConfig struct { - MasterIp string + MasterIP string States []string } func cloudInitConfig(config *MinionConfig) string { c, err := cloudinit.New("focal") - if err != nil { panic(err) } @@ -32,27 +31,25 @@ schedule: minutes: 15 grains: - role: github-action-runner`, 0644) + role: github-action-runner`, 0o644) // I'm really trying to avoid bringing in any templating library to // write this configuration, so I'm going to write each requested state to its // own conf, which Salt will merge when the minion starts // Sorry for _, state := range config.States { - c.AddRunTextFile(fmt.Sprintf("/etc/salt/minion.d/gha_runner_state_%s.conf", state), fmt.Sprintf("grains:\n gha_runner_states:\n - %s", state), 0644) + c.AddRunTextFile(fmt.Sprintf("/etc/salt/minion.d/gha_runner_state_%s.conf", state), fmt.Sprintf("grains:\n gha_runner_states:\n - %s", state), 0o644) } - c.AddRunCmd(fmt.Sprintf("echo master: %s > /etc/salt/minion.d/master.conf", config.MasterIp)) + c.AddRunCmd(fmt.Sprintf("echo master: %s > /etc/salt/minion.d/master.conf", config.MasterIP)) c.AddRunCmd("systemctl daemon-reload") c.AddRunCmd("systemctl enable salt-minion.service") c.AddRunCmd("systemctl restart --no-block salt-minion.service") script, err := c.RenderScript() - if err != nil { panic(err) } return script - } diff --git a/pulumi/src/github-actions/main.go b/pulumi/src/github-actions/main.go index 8cd819e..10616c7 100644 --- a/pulumi/src/github-actions/main.go +++ b/pulumi/src/github-actions/main.go @@ -14,19 +14,19 @@ type GitHubConfig struct { } // GitHubActionRunnerConfig is the struct we allow in the stack configuration -// to describe the GitHubActionRunner we provision +// to describe the GitHubActionRunner we provision. type GitHubActionRunnerConfig struct { Facility equinix.Facility Plan equinix.Plan States []string } -// GitHubActionRunner is the return struct for CreateSaltMaster +// GitHubActionRunner is the return struct for CreateSaltMaster. type GitHubActionRunners struct { Devices []equinix.Device } -// CreateGitHubActionRunner Provisions a GitHub Action Runner +// CreateGitHubActionRunner Provisions a GitHub Action Runner. func CreateGitHubActionRunners(ctx *pulumi.Context, infrastructure internal.Infrastructure) (GitHubActionRunners, error) { metalConfig := config.New(ctx, "equinix-metal") projectID := metalConfig.Require("projectId") @@ -50,16 +50,15 @@ func CreateGitHubActionRunners(ctx *pulumi.Context, infrastructure internal.Infr pulumi.String("role:github-action-runner"), }, BillingCycle: equinix.BillingCycleHourly, - UserData: pulumi.All(infrastructure.SaltMasterIp, runner.States).ApplyT(func(args []interface{}) string { + UserData: pulumi.All(infrastructure.SaltMasterIP, runner.States).ApplyT(func(args []interface{}) string { return cloudInitConfig(&MinionConfig{ - MasterIp: args[0].(string), + MasterIP: args[0].(string), States: args[1].([]string), }) }).(pulumi.StringOutput), } device, err := equinix.NewDevice(ctx, fmt.Sprintf("github-action-runner-%d", i), &deviceArgs) - if err != nil { return GitHubActionRunners{}, err } diff --git a/pulumi/src/internal/main.go b/pulumi/src/internal/main.go index 047b3a7..2ac4ed0 100644 --- a/pulumi/src/internal/main.go +++ b/pulumi/src/internal/main.go @@ -10,5 +10,5 @@ import ( // with DNS zone being the first use-case. type Infrastructure struct { Zone ns1.LookupZoneResult - SaltMasterIp pulumi.StringOutput + SaltMasterIP pulumi.StringOutput } diff --git a/pulumi/src/main.go b/pulumi/src/main.go index 9b58c00..6261ca2 100644 --- a/pulumi/src/main.go +++ b/pulumi/src/main.go @@ -11,7 +11,7 @@ import ( func main() { pulumi.Run(func(ctx *pulumi.Context) error { - zone, err := tinkdns.ManageDns(ctx) + zone, err := tinkdns.ManageDNS(ctx) if err != nil { return err } @@ -21,12 +21,11 @@ func main() { } saltMaster, err := master.CreateSaltMaster(ctx, infrastructure) - if err != nil { return err } - infrastructure.SaltMasterIp = saltMaster.Device.AccessPrivateIpv4 + infrastructure.SaltMasterIP = saltMaster.Device.AccessPrivateIpv4 _, err = runners.CreateGitHubActionRunners(ctx, infrastructure) @@ -34,7 +33,7 @@ func main() { return err } - _, err = assets.CreateAssetsDns(ctx, infrastructure) + _, err = assets.CreateDNS(ctx, infrastructure) if err != nil { return err } diff --git a/pulumi/src/saltstack/master/cloud-init.go b/pulumi/src/saltstack/master/cloud-init.go index bb686e2..8720928 100644 --- a/pulumi/src/saltstack/master/cloud-init.go +++ b/pulumi/src/saltstack/master/cloud-init.go @@ -21,7 +21,6 @@ type BootstrapConfig struct { func cloudInitConfig(config *BootstrapConfig) string { c, err := cloudinit.New("focal") - if err != nil { panic(err) } @@ -54,7 +53,7 @@ ext_pillar: - git: - main https://github.com/tinkerbell/infrastructure: - root: saltstack/pillar - - env: main`, 0644) + - env: main`, 0o644) c.AddRunTextFile("/etc/salt/minion.d/minion.conf", `autosign_grains: - role @@ -66,7 +65,7 @@ schedule: minutes: 15 grains: - role: master`, 0644) + role: master`, 0o644) c.AddRunCmd("PRIVATE_IP=$(curl -s https://metadata.platformequinix.com/metadata | jq -r '.network.addresses | map(select(.public==false)) | first | .address')") @@ -84,16 +83,16 @@ grains: 'G@role:github-action-runner': - github -`, 0644) +`, 0o644) c.AddRunCmd("mkdir -p /srv/pillar/teleport") - c.AddRunTextFile("/srv/pillar/teleport/init.sls", fmt.Sprintf("teleport:\n domain: %s\n clientId: %s\n clientSecret: %s\n", config.teleportDomain, config.teleportClientID, config.teleportClientSecret), 0400) - c.AddRunTextFile("/srv/pillar/teleport/node.sls", fmt.Sprintf("teleport:\n peerToken: %s\n", config.teleportPeerToken), 0400) - c.AddRunTextFile("/srv/pillar/github.sls", fmt.Sprintf("github:\n username: %s\n accessToken: %s\n", config.githubUsername, config.githubAccessToken), 0400) - c.AddRunTextFile("/srv/pillar/aws.sls", fmt.Sprintf("s3:\n keyid: %s\n key: %s\n location: %s\n bucketName: %s\n", config.awsAccessKeyID, config.awsSecretAccessKey, config.awsBucketLocation, config.awsBucketName), 0400) + c.AddRunTextFile("/srv/pillar/teleport/init.sls", fmt.Sprintf("teleport:\n domain: %s\n clientId: %s\n clientSecret: %s\n", config.teleportDomain, config.teleportClientID, config.teleportClientSecret), 0o400) + c.AddRunTextFile("/srv/pillar/teleport/node.sls", fmt.Sprintf("teleport:\n peerToken: %s\n", config.teleportPeerToken), 0o400) + c.AddRunTextFile("/srv/pillar/github.sls", fmt.Sprintf("github:\n username: %s\n accessToken: %s\n", config.githubUsername, config.githubAccessToken), 0o400) + c.AddRunTextFile("/srv/pillar/aws.sls", fmt.Sprintf("s3:\n keyid: %s\n key: %s\n location: %s\n bucketName: %s\n", config.awsAccessKeyID, config.awsSecretAccessKey, config.awsBucketLocation, config.awsBucketName), 0o400) // https://github.com/saltstack/salt/issues/60222 - c.AddRunTextFile("/srv/pillar/aws-eurgh.sls", fmt.Sprintf("s3.keyid: %s\ns3.key: %s\ns3.location: %s\ns3.bucketName: %s\n", config.awsAccessKeyID, config.awsSecretAccessKey, config.awsBucketLocation, config.awsBucketName), 0400) + c.AddRunTextFile("/srv/pillar/aws-eurgh.sls", fmt.Sprintf("s3.keyid: %s\ns3.key: %s\ns3.location: %s\ns3.bucketName: %s\n", config.awsAccessKeyID, config.awsSecretAccessKey, config.awsBucketLocation, config.awsBucketName), 0o400) c.AddRunCmd("echo interface: ${PRIVATE_IP} > /etc/salt/master.d/private-interface.conf") c.AddRunCmd("echo master: ${PRIVATE_IP} > /etc/salt/minion.d/master.conf") @@ -106,11 +105,9 @@ grains: c.AddRunCmd("systemctl restart --no-block salt-minion.service") script, err := c.RenderScript() - if err != nil { panic(err) } return script - } diff --git a/pulumi/src/saltstack/master/main.go b/pulumi/src/saltstack/master/main.go index 1ea39f9..f0c827e 100644 --- a/pulumi/src/saltstack/master/main.go +++ b/pulumi/src/saltstack/master/main.go @@ -12,13 +12,13 @@ import ( ) // SaltMasterConfig is the struct we allow in the stack configuration -// to describe the SaltMaster we provision +// to describe the SaltMaster we provision. type SaltMasterConfig struct { Facility equinix.Facility Plan equinix.Plan } -// SaltMaster is the return struct for CreateSaltMaster +// SaltMaster is the return struct for CreateSaltMaster. type SaltMaster struct { Device equinix.Device } @@ -41,7 +41,7 @@ type AwsConfig struct { BucketLocation string } -// CreateSaltMaster Provisions a SaltMaster +// CreateSaltMaster Provisions a SaltMaster. func CreateSaltMaster(ctx *pulumi.Context, infrastructure internal.Infrastructure) (SaltMaster, error) { metalConfig := config.New(ctx, "equinix-metal") projectID := metalConfig.Require("projectId") @@ -55,6 +55,9 @@ func CreateSaltMaster(ctx *pulumi.Context, infrastructure internal.Infrastructur ProjectId: pulumi.String(projectID), Quantity: pulumi.Int(1), }) + if err != nil { + return SaltMaster{}, err + } var teleportConfig TeleportConfig stackConfig.RequireObject("teleport", &teleportConfig) @@ -62,7 +65,6 @@ func CreateSaltMaster(ctx *pulumi.Context, infrastructure internal.Infrastructur // Generate random PeerToken for Teleport cluster peerToken, err := random.NewRandomUuid(ctx, "teleport-peer-token", nil) - if err != nil { return SaltMaster{}, err } diff --git a/pulumi/src/utils.go b/pulumi/src/utils.go deleted file mode 100644 index eb0c34f..0000000 --- a/pulumi/src/utils.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/pulumi/pulumi/sdk/v2/go/pulumi" -) - -func StackName(ctx *pulumi.Context, name string) string { - - return fmt.Sprintf("%s-%s", ctx.Stack(), name) -}