diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml index 80a84b6a..c2d299b9 100755 --- a/.github/workflows/build-and-test.yaml +++ b/.github/workflows/build-and-test.yaml @@ -13,7 +13,7 @@ on: - cron: '0 19 * * 1-5' env: - DEFAULT_GO_VERSION: ^1.22.0 + DEFAULT_GO_VERSION: ^1.25.0 GITHUB_USERNAME: ${{ secrets.EC2_BOT_GITHUB_USERNAME }} GITHUB_TOKEN: ${{ secrets.EC2_BOT_GITHUB_TOKEN }} WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }} @@ -71,7 +71,7 @@ jobs: cache: false - name: Set up golangci-lint - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v7 with: version: latest args: --timeout=5m diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index b760aa12..7c44bd87 100755 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -10,7 +10,7 @@ permissions: id-token: write env: - DEFAULT_GO_VERSION: ^1.22.0 + DEFAULT_GO_VERSION: ^1.25.0 GITHUB_USERNAME: ${{ secrets.EC2_BOT_GITHUB_USERNAME }} GITHUB_TOKEN: ${{ secrets.EC2_BOT_GITHUB_TOKEN }} WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }} diff --git a/Dockerfile b/Dockerfile index 7d879865..bc9f09dc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM golang:1.22 as builder +FROM --platform=$BUILDPLATFORM golang:1.25 as builder ## GOLANG env ARG GOPROXY="https://proxy.golang.org|direct" diff --git a/Dockerfile.windows b/Dockerfile.windows index 092eb04e..ad86ea36 100644 --- a/Dockerfile.windows +++ b/Dockerfile.windows @@ -1,7 +1,7 @@ ARG WINDOWS_VERSION=1809 # Build the manager binary -FROM --platform=windows/amd64 golang:1.22 as builder +FROM --platform=windows/amd64 golang:1.25 as builder ## GOLANG env ENV GO111MODULE="on" CGO_ENABLED="0" GOOS="windows" GOARCH="amd64" diff --git a/README.md b/README.md index 64b03109..fb4aee51 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ kubernetes - + go-version diff --git a/cmd/node-termination-handler.go b/cmd/node-termination-handler.go index edbd1672..01626894 100644 --- a/cmd/node-termination-handler.go +++ b/cmd/node-termination-handler.go @@ -279,11 +279,12 @@ func main() { asgLaunchHandler := launch.New(interruptionEventStore, *node, nthConfig, metrics, recorder, clientset) drainCordonHander := draincordon.New(interruptionEventStore, *node, nthConfig, nodeMetadata, metrics, recorder) +InterruptionLoop: for range time.NewTicker(1 * time.Second).C { select { case <-signalChan: // Exit interruption loop if a SIGTERM is received or the channel is closed - break + break InterruptionLoop default: EventLoop: for event, ok := interruptionEventStore.GetActiveEvent(); ok; event, ok = interruptionEventStore.GetActiveEvent() { @@ -320,7 +321,7 @@ func handleRebootUncordon(nodeName string, interruptionEventStore *interruptione } err = node.UncordonIfRebooted(nodeName) if err != nil { - return fmt.Errorf("Unable to complete node label actions: %w", err) + return fmt.Errorf("unable to complete node label actions: %w", err) } interruptionEventStore.IgnoreEvent(eventID) return nil diff --git a/go.mod b/go.mod index 2a01b7b8..41f569e8 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/aws/aws-node-termination-handler -go 1.22.0 +go 1.25 -toolchain go1.22.2 +toolchain go1.25.5 require ( github.com/Masterminds/sprig/v3 v3.2.3 diff --git a/pkg/config/config.go b/pkg/config/config.go index 9de5f69f..6498dc81 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -316,8 +316,12 @@ func ParseCliArgs() (config Config, err error) { } // client-go expects these to be set in env vars - os.Setenv(kubernetesServiceHostConfigKey, config.KubernetesServiceHost) - os.Setenv(kubernetesServicePortConfigKey, config.KubernetesServicePort) + if err := os.Setenv(kubernetesServiceHostConfigKey, config.KubernetesServiceHost); err != nil { + return config, fmt.Errorf("failed to set %s environment variable: %w", kubernetesServiceHostConfigKey, err) + } + if err := os.Setenv(kubernetesServicePortConfigKey, config.KubernetesServicePort); err != nil { + return config, fmt.Errorf("failed to set %s environment variable: %w", kubernetesServicePortConfigKey, err) + } return config, err } diff --git a/pkg/ec2metadata/ec2metadata.go b/pkg/ec2metadata/ec2metadata.go index 036a6347..c1e87557 100644 --- a/pkg/ec2metadata/ec2metadata.go +++ b/pkg/ec2metadata/ec2metadata.go @@ -139,16 +139,16 @@ func New(metadataURL string, tries int) *Service { func (e *Service) GetScheduledMaintenanceEvents() ([]ScheduledEventDetail, error) { resp, err := e.Request(ScheduledEventPath) if resp != nil && (resp.StatusCode < 200 || resp.StatusCode >= 300) { - return nil, fmt.Errorf("Metadata request received http status code: %d", resp.StatusCode) + return nil, fmt.Errorf("metadata request received http status code: %d", resp.StatusCode) } if err != nil { - return nil, fmt.Errorf("Unable to parse metadata response: %w", err) + return nil, fmt.Errorf("unable to parse metadata response: %w", err) } - defer resp.Body.Close() + defer func() { _ = resp.Body.Close() }() var scheduledEvents []ScheduledEventDetail err = json.NewDecoder(resp.Body).Decode(&scheduledEvents) if err != nil { - return nil, fmt.Errorf("Could not decode json retrieved from imds: %w", err) + return nil, fmt.Errorf("could not decode json retrieved from imds: %w", err) } return scheduledEvents, nil } @@ -160,16 +160,16 @@ func (e *Service) GetSpotITNEvent() (instanceAction *InstanceAction, err error) if resp != nil && resp.StatusCode == 404 { return nil, nil } else if resp != nil && (resp.StatusCode < 200 || resp.StatusCode >= 300) { - return nil, fmt.Errorf("Metadata request received http status code: %d", resp.StatusCode) + return nil, fmt.Errorf("metadata request received http status code: %d", resp.StatusCode) } if err != nil { - return nil, fmt.Errorf("Unable to parse metadata response: %w", err) + return nil, fmt.Errorf("unable to parse metadata response: %w", err) } - defer resp.Body.Close() + defer func() { _ = resp.Body.Close() }() err = json.NewDecoder(resp.Body).Decode(&instanceAction) if err != nil { - return nil, fmt.Errorf("Could not decode instance action response: %w", err) + return nil, fmt.Errorf("could not decode instance action response: %w", err) } return instanceAction, nil } @@ -181,16 +181,16 @@ func (e *Service) GetRebalanceRecommendationEvent() (rebalanceRec *RebalanceReco if resp != nil && resp.StatusCode == 404 { return nil, nil } else if resp != nil && (resp.StatusCode < 200 || resp.StatusCode >= 300) { - return nil, fmt.Errorf("Metadata request received http status code: %d", resp.StatusCode) + return nil, fmt.Errorf("metadata request received http status code: %d", resp.StatusCode) } if err != nil { - return nil, fmt.Errorf("Unable to parse metadata response: %w", err) + return nil, fmt.Errorf("unable to parse metadata response: %w", err) } - defer resp.Body.Close() + defer func() { _ = resp.Body.Close() }() err = json.NewDecoder(resp.Body).Decode(&rebalanceRec) if err != nil { - return nil, fmt.Errorf("Could not decode rebalance recommendation response: %w", err) + return nil, fmt.Errorf("could not decode rebalance recommendation response: %w", err) } return rebalanceRec, nil } @@ -203,16 +203,16 @@ func (e *Service) GetASGTargetLifecycleState() (state string, err error) { if resp != nil && resp.StatusCode == 404 { return "", nil } else if resp != nil && (resp.StatusCode < 200 || resp.StatusCode >= 300) { - return "", fmt.Errorf("Metadata request received http status code: %d", resp.StatusCode) + return "", fmt.Errorf("metadata request received http status code: %d", resp.StatusCode) } if err != nil { - return "", fmt.Errorf("Unable to parse metadata response: %w", err) + return "", fmt.Errorf("unable to parse metadata response: %w", err) } - defer resp.Body.Close() + defer func() { _ = resp.Body.Close() }() body, err := io.ReadAll(resp.Body) if err != nil { - return "", fmt.Errorf("Unable to parse http response. Status code: %d. %w", resp.StatusCode, err) + return "", fmt.Errorf("unable to parse http response. Status code: %d. %w", resp.StatusCode, err) } return string(body), nil } @@ -222,19 +222,19 @@ func (e *Service) GetMetadataInfo(path string, allowMissing bool) (info string, metadataInfo := "" resp, err := e.Request(path) if err != nil { - return "", fmt.Errorf("Unable to parse metadata response: %w", err) + return "", fmt.Errorf("unable to parse metadata response: %w", err) } if resp != nil { - defer resp.Body.Close() + defer func() { _ = resp.Body.Close() }() body, err := io.ReadAll(resp.Body) if err != nil { - return "", fmt.Errorf("Unable to parse http response. Status code: %d. %w", resp.StatusCode, err) + return "", fmt.Errorf("unable to parse http response. Status code: %d. %w", resp.StatusCode, err) } metadataInfo = string(body) if resp.StatusCode < 200 || resp.StatusCode >= 300 { if resp.StatusCode != 404 || !allowMissing { log.Info().Msgf("Metadata response status code: %d. Body: %s", resp.StatusCode, metadataInfo) - return "", fmt.Errorf("Metadata request received http status code: %d", resp.StatusCode) + return "", fmt.Errorf("metadata request received http status code: %d", resp.StatusCode) } else { return "", nil } @@ -249,7 +249,7 @@ func (e *Service) GetMetadataInfo(path string, allowMissing bool) (info string, func (e *Service) Request(contextPath string) (*http.Response, error) { req, err := http.NewRequest(http.MethodGet, e.metadataURL+contextPath, nil) if err != nil { - return nil, fmt.Errorf("Unable to construct an http get request to IDMS for %s: %w", e.metadataURL+contextPath, err) + return nil, fmt.Errorf("unable to construct an http get request to IDMS for %s: %w", e.metadataURL+contextPath, err) } var resp *http.Response for i := 0; i < tokenRetryAttempts; i++ { @@ -274,7 +274,7 @@ func (e *Service) Request(contextPath string) (*http.Response, error) { } resp, err = retry(e.tries, 2*time.Second, httpReq) if err != nil { - return nil, fmt.Errorf("Unable to get a response from IMDS: %w", err) + return nil, fmt.Errorf("unable to get a response from IMDS: %w", err) } if resp != nil && resp.StatusCode == 401 { e.Lock() @@ -297,7 +297,7 @@ func (e *Service) Request(contextPath string) (*http.Response, error) { func (e *Service) getV2Token() (string, int, error) { req, err := http.NewRequest(http.MethodPut, e.metadataURL+tokenRefreshPath, nil) if err != nil { - return "", -1, fmt.Errorf("Unable to construct http put request to retrieve imdsv2 token: %w", err) + return "", -1, fmt.Errorf("unable to construct http put request to retrieve imdsv2 token: %w", err) } req.Header.Add(tokenTTLHeader, strconv.Itoa(tokenTTL)) httpReq := func() (*http.Response, error) { @@ -308,13 +308,13 @@ func (e *Service) getV2Token() (string, int, error) { if err != nil { return "", -1, err } - defer resp.Body.Close() + defer func() { _ = resp.Body.Close() }() if resp.StatusCode < 200 || resp.StatusCode >= 300 { - return "", -1, fmt.Errorf("Received an http status code %d", resp.StatusCode) + return "", -1, fmt.Errorf("received an http status code %d", resp.StatusCode) } token, err := io.ReadAll(resp.Body) if err != nil { - return "", -1, fmt.Errorf("Unable to read token response from IMDSv2: %w", err) + return "", -1, fmt.Errorf("unable to read token response from IMDSv2: %w", err) } ttl, err := ttlHeaderToInt(resp) if err != nil { @@ -327,7 +327,7 @@ func (e *Service) getV2Token() (string, int, error) { func ttlHeaderToInt(resp *http.Response) (int, error) { ttl := resp.Header.Get(tokenTTLHeader) if ttl == "" { - return -1, fmt.Errorf("No token TTL header found") + return -1, fmt.Errorf("no token TTL header found") } ttlInt, err := strconv.Atoi(ttl) if err != nil { diff --git a/pkg/ec2metadata/ec2metadata_internal_test.go b/pkg/ec2metadata/ec2metadata_internal_test.go index 0e3999e4..89cbf26b 100644 --- a/pkg/ec2metadata/ec2metadata_internal_test.go +++ b/pkg/ec2metadata/ec2metadata_internal_test.go @@ -27,8 +27,8 @@ import ( ) func TestRetry(t *testing.T) { - var numRetries int = 3 - var errorMsg string = "Request failed" + var numRetries = 3 + var errorMsg = "Request failed" var requestCount int request := func() (*http.Response, error) { diff --git a/pkg/ec2metadata/ec2metadata_test.go b/pkg/ec2metadata/ec2metadata_test.go index 92660a23..87f89634 100644 --- a/pkg/ec2metadata/ec2metadata_test.go +++ b/pkg/ec2metadata/ec2metadata_test.go @@ -25,7 +25,7 @@ import ( ) func TestRequestV1(t *testing.T) { - var requestPath string = "/some/path" + var requestPath = "/some/path" server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { if req.URL.String() == "/latest/api/token" { @@ -55,7 +55,7 @@ func TestRequestV1(t *testing.T) { } func TestRequestV2(t *testing.T) { - var requestPath string = "/some/path" + var requestPath = "/some/path" server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Add("X-aws-ec2-metadata-token-ttl-seconds", "100") @@ -89,7 +89,7 @@ func TestRequestV2(t *testing.T) { } func TestRequestFailure(t *testing.T) { - var requestPath string = "/some/path" + var requestPath = "/some/path" imds := ec2metadata.New("notadomain", 1) _, err := imds.Request(requestPath) @@ -97,7 +97,7 @@ func TestRequestFailure(t *testing.T) { } func TestRequest500(t *testing.T) { - var requestPath string = "/some/path" + var requestPath = "/some/path" server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { if req.URL.String() == "/latest/api/token" { @@ -118,7 +118,7 @@ func TestRequest500(t *testing.T) { } func TestRequest401(t *testing.T) { - var requestPath string = "/some/path" + var requestPath = "/some/path" tokenGenerationCounter := 0 server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { @@ -161,7 +161,7 @@ func TestGetSpotITNEventSuccess(t *testing.T) { time = "2020-02-07T14:55:55Z" instanceAction = "terminate" ) - var requestPath string = "/latest/meta-data/spot/instance-action" + var requestPath = "/latest/meta-data/spot/instance-action" server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Add("X-aws-ec2-metadata-token-ttl-seconds", "100") @@ -173,10 +173,10 @@ func TestGetSpotITNEventSuccess(t *testing.T) { } h.Equals(t, req.Header.Get("X-aws-ec2-metadata-token"), "token") h.Equals(t, req.URL.String(), requestPath) - _, err := rw.Write([]byte(fmt.Sprintf(`{ + _, err := fmt.Fprintf(rw, `{ "action": "%s", "time": "%s" - }`, instanceAction, time))) + }`, instanceAction, time) h.Ok(t, err) })) defer server.Close() @@ -195,7 +195,7 @@ func TestGetSpotITNEventSuccess(t *testing.T) { } func TestGetSpotITNEvent404Success(t *testing.T) { - var requestPath string = "/latest/meta-data/spot/instance-action" + var requestPath = "/latest/meta-data/spot/instance-action" server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Add("X-aws-ec2-metadata-token-ttl-seconds", "100") @@ -220,7 +220,7 @@ func TestGetSpotITNEvent404Success(t *testing.T) { } func TestGetSpotITNEventBadJSON(t *testing.T) { - var requestPath string = "/latest/meta-data/spot/instance-action" + var requestPath = "/latest/meta-data/spot/instance-action" server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Add("X-aws-ec2-metadata-token-ttl-seconds", "100") @@ -245,7 +245,7 @@ func TestGetSpotITNEventBadJSON(t *testing.T) { } func TestGetSpotITNEvent500Failure(t *testing.T) { - var requestPath string = "/latest/meta-data/spot/instance-action" + var requestPath = "/latest/meta-data/spot/instance-action" server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Add("X-aws-ec2-metadata-token-ttl-seconds", "100") @@ -285,7 +285,7 @@ func TestGetScheduledMaintenanceEventsSuccess(t *testing.T) { eventId = "instance-event-0d59937288b749b32" state = "active" ) - var requestPath string = "/latest/meta-data/events/maintenance/scheduled" + var requestPath = "/latest/meta-data/events/maintenance/scheduled" server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Add("X-aws-ec2-metadata-token-ttl-seconds", "100") @@ -297,7 +297,7 @@ func TestGetScheduledMaintenanceEventsSuccess(t *testing.T) { } h.Equals(t, req.Header.Get("X-aws-ec2-metadata-token"), "token") h.Equals(t, req.URL.String(), requestPath) - _, err := rw.Write([]byte(fmt.Sprintf(`[ + _, err := fmt.Fprintf(rw, `[ { "NotBefore" : "%s", "Code" : "%s", @@ -306,7 +306,7 @@ func TestGetScheduledMaintenanceEventsSuccess(t *testing.T) { "NotAfter" : "%s", "State" : "%s" } - ]`, notBefore, code, description, eventId, notAfter, state))) + ]`, notBefore, code, description, eventId, notAfter, state) h.Ok(t, err) })) defer server.Close() @@ -331,7 +331,7 @@ func TestGetScheduledMaintenanceEventsSuccess(t *testing.T) { } func TestGetScheduledMaintenanceEvents500Failure(t *testing.T) { - var requestPath string = "/latest/meta-data/events/maintenance/scheduled" + var requestPath = "/latest/meta-data/events/maintenance/scheduled" server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Add("X-aws-ec2-metadata-token-ttl-seconds", "100") @@ -355,7 +355,7 @@ func TestGetScheduledMaintenanceEvents500Failure(t *testing.T) { } func TestGetScheduledMaintenanceEventsBadJSON(t *testing.T) { - var requestPath string = "/latest/meta-data/events/maintenance/scheduled" + var requestPath = "/latest/meta-data/events/maintenance/scheduled" server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Add("X-aws-ec2-metadata-token-ttl-seconds", "100") @@ -403,9 +403,9 @@ func TestGetRebalanceRecommendationEventSuccess(t *testing.T) { } h.Equals(t, req.Header.Get("X-aws-ec2-metadata-token"), "token") h.Equals(t, req.URL.String(), requestPath) - _, err := rw.Write([]byte(fmt.Sprintf(`{ + _, err := fmt.Fprintf(rw, `{ "noticeTime": "%s" - }`, noticeTime))) + }`, noticeTime) h.Ok(t, err) })) defer server.Close() @@ -590,7 +590,7 @@ func TestGetASGTargetLifecycleStateRequestFailure(t *testing.T) { } func TestGetMetadataServiceRequest404(t *testing.T) { - var requestPath string = "/latest/meta-data/instance-type" + var requestPath = "/latest/meta-data/instance-type" server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Add("X-aws-ec2-metadata-token-ttl-seconds", "100") @@ -615,7 +615,7 @@ func TestGetMetadataServiceRequest404(t *testing.T) { } func TestGetMetadataServiceRequest404AllowMissing(t *testing.T) { - var requestPath string = "/latest/meta-data/instance-type" + var requestPath = "/latest/meta-data/instance-type" server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Add("X-aws-ec2-metadata-token-ttl-seconds", "100") @@ -640,7 +640,7 @@ func TestGetMetadataServiceRequest404AllowMissing(t *testing.T) { } func TestGetMetadataServiceRequest500AllowMissing(t *testing.T) { - var requestPath string = "/latest/meta-data/instance-type" + var requestPath = "/latest/meta-data/instance-type" server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Add("X-aws-ec2-metadata-token-ttl-seconds", "100") @@ -673,7 +673,7 @@ func TestGetMetadataServiceRequestFailure(t *testing.T) { } func TestGetMetadataServiceSuccess(t *testing.T) { - var requestPath string = "/latest/meta-data/instance-type" + var requestPath = "/latest/meta-data/instance-type" server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Add("X-aws-ec2-metadata-token-ttl-seconds", "100") diff --git a/pkg/logging/versioned.go b/pkg/logging/versioned.go index 95bcb72f..d6328819 100644 --- a/pkg/logging/versioned.go +++ b/pkg/logging/versioned.go @@ -102,6 +102,6 @@ func SetFormatVersion(version int) error { return nil default: VersionedMsgs = versionedMsgsV1{} - return fmt.Errorf("Unrecognized log format version: %d, using version 1", version) + return fmt.Errorf("unrecognized log format version: %d, using version 1", version) } } diff --git a/pkg/monitor/asglifecycle/asg-lifecycle-monitor.go b/pkg/monitor/asglifecycle/asg-lifecycle-monitor.go index a623ae96..36474bea 100644 --- a/pkg/monitor/asglifecycle/asg-lifecycle-monitor.go +++ b/pkg/monitor/asglifecycle/asg-lifecycle-monitor.go @@ -78,7 +78,7 @@ func (m ASGLifecycleMonitor) checkForASGTargetLifecycleStateNotice() (*monitor.I // There's no EventID returned, so we'll create it using a hash to prevent duplicates. hash := sha256.New() - if _, err = hash.Write([]byte(fmt.Sprintf("%s:%s", state, interruptionTime))); err != nil { + if _, err = fmt.Fprintf(hash, "%s:%s", state, interruptionTime); err != nil { return nil, fmt.Errorf("There was a problem creating an event ID from the event: %w", err) } diff --git a/pkg/monitor/rebalancerecommendation/rebalance-recommendation-monitor.go b/pkg/monitor/rebalancerecommendation/rebalance-recommendation-monitor.go index d0095c78..c8a39c76 100644 --- a/pkg/monitor/rebalancerecommendation/rebalance-recommendation-monitor.go +++ b/pkg/monitor/rebalancerecommendation/rebalance-recommendation-monitor.go @@ -77,7 +77,7 @@ func (m RebalanceRecommendationMonitor) checkForRebalanceRecommendation() (*moni // There's no EventID returned so we'll create it using a hash to prevent duplicates. hash := sha256.New() - _, err = hash.Write([]byte(fmt.Sprintf("%v", rebalanceRecommendation))) + _, err = fmt.Fprintf(hash, "%v", rebalanceRecommendation) if err != nil { return nil, fmt.Errorf("There was a problem creating an event ID from the event: %w", err) } diff --git a/pkg/monitor/scheduledevent/scheduled-event-monitor_test.go b/pkg/monitor/scheduledevent/scheduled-event-monitor_test.go index fbe3a26f..f8e53ffc 100644 --- a/pkg/monitor/scheduledevent/scheduled-event-monitor_test.go +++ b/pkg/monitor/scheduledevent/scheduled-event-monitor_test.go @@ -54,7 +54,7 @@ func oneSecondAgo() time.Time { } func TestMonitor_Success(t *testing.T) { - var requestPath string = ec2metadata.ScheduledEventPath + var requestPath = ec2metadata.ScheduledEventPath server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { if imdsV2TokenPath == req.URL.String() { @@ -103,7 +103,7 @@ func TestMonitor_Success(t *testing.T) { } func TestMonitor_CanceledEvent(t *testing.T) { - var requestPath string = ec2metadata.ScheduledEventPath + var requestPath = ec2metadata.ScheduledEventPath var state = "canceled" server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { if imdsV2TokenPath == req.URL.String() { @@ -158,7 +158,7 @@ func TestMonitor_CanceledEvent(t *testing.T) { } func TestMonitor_MetadataParseFailure(t *testing.T) { - var requestPath string = ec2metadata.ScheduledEventPath + var requestPath = ec2metadata.ScheduledEventPath server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { if imdsV2TokenPath == req.URL.String() { @@ -179,7 +179,7 @@ func TestMonitor_MetadataParseFailure(t *testing.T) { } func TestMonitor_404Response(t *testing.T) { - var requestPath string = ec2metadata.ScheduledEventPath + var requestPath = ec2metadata.ScheduledEventPath server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { if imdsV2TokenPath == req.URL.String() { @@ -202,7 +202,7 @@ func TestMonitor_404Response(t *testing.T) { } func TestMonitor_StartTimeParseFail(t *testing.T) { - var requestPath string = ec2metadata.ScheduledEventPath + var requestPath = ec2metadata.ScheduledEventPath server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { if imdsV2TokenPath == req.URL.String() { rw.WriteHeader(403) @@ -231,7 +231,7 @@ func TestMonitor_StartTimeParseFail(t *testing.T) { } func TestMonitor_EndTimeParseFail(t *testing.T) { - var requestPath string = ec2metadata.ScheduledEventPath + var requestPath = ec2metadata.ScheduledEventPath server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { if imdsV2TokenPath == req.URL.String() { rw.WriteHeader(403) diff --git a/pkg/monitor/spotitn/spot-itn-monitor.go b/pkg/monitor/spotitn/spot-itn-monitor.go index 061577e7..c9f1954e 100644 --- a/pkg/monitor/spotitn/spot-itn-monitor.go +++ b/pkg/monitor/spotitn/spot-itn-monitor.go @@ -79,7 +79,7 @@ func (m SpotInterruptionMonitor) checkForSpotInterruptionNotice() (*monitor.Inte // There's no EventID returned so we'll create it using a hash to prevent duplicates. hash := sha256.New() - _, err = hash.Write([]byte(fmt.Sprintf("%v", instanceAction))) + _, err = fmt.Fprintf(hash, "%v", instanceAction) if err != nil { return nil, fmt.Errorf("There was a problem creating an event ID from the event: %w", err) } diff --git a/pkg/monitor/sqsevent/sqs-monitor.go b/pkg/monitor/sqsevent/sqs-monitor.go index 84440d4c..b0e7cdd2 100644 --- a/pkg/monitor/sqsevent/sqs-monitor.go +++ b/pkg/monitor/sqsevent/sqs-monitor.go @@ -211,21 +211,23 @@ func (m SQSMonitor) processEventBridgeEvent(eventBridgeEvent *EventBridgeEvent, interruptionEvent, err = nil, fmt.Errorf("unmarshaling message, %s, from ASG lifecycle event: %w", *message.MessageId, err) interruptionEventWrappers = append(interruptionEventWrappers, InterruptionEventWrapper{interruptionEvent, err}) } - if lifecycleEvent.LifecycleTransition == ASGLaunchingLifecycleTransition { + switch lifecycleEvent.LifecycleTransition { + case ASGLaunchingLifecycleTransition: interruptionEvent, err = m.createAsgInstanceLaunchEvent(eventBridgeEvent, message) interruptionEventWrappers = append(interruptionEventWrappers, InterruptionEventWrapper{interruptionEvent, err}) - } else if lifecycleEvent.LifecycleTransition == ASGTerminatingLifecycleTransition { + case ASGTerminatingLifecycleTransition: interruptionEvent, err = m.asgTerminationToInterruptionEvent(eventBridgeEvent, message) interruptionEventWrappers = append(interruptionEventWrappers, InterruptionEventWrapper{interruptionEvent, err}) } return interruptionEventWrappers case "aws.ec2": - if eventBridgeEvent.DetailType == "EC2 Instance State-change Notification" { + switch eventBridgeEvent.DetailType { + case "EC2 Instance State-change Notification": interruptionEvent, err = m.ec2StateChangeToInterruptionEvent(eventBridgeEvent, message) - } else if eventBridgeEvent.DetailType == "EC2 Spot Instance Interruption Warning" { + case "EC2 Spot Instance Interruption Warning": interruptionEvent, err = m.spotITNTerminationToInterruptionEvent(eventBridgeEvent, message) - } else if eventBridgeEvent.DetailType == "EC2 Instance Rebalance Recommendation" { + case "EC2 Instance Rebalance Recommendation": interruptionEvent, err = m.rebalanceRecommendationToInterruptionEvent(eventBridgeEvent, message) } return append(interruptionEventWrappers, InterruptionEventWrapper{interruptionEvent, err}) diff --git a/pkg/monitor/sqsevent/sqs-monitor_internal_test.go b/pkg/monitor/sqsevent/sqs-monitor_internal_test.go index c7caa10f..ff209746 100644 --- a/pkg/monitor/sqsevent/sqs-monitor_internal_test.go +++ b/pkg/monitor/sqsevent/sqs-monitor_internal_test.go @@ -29,7 +29,7 @@ func TestGetTime_Success(t *testing.T) { testTime, err := time.Parse(time.RFC3339, testTimeStr) h.Ok(t, err) asgLifecycleTime := EventBridgeEvent{Time: testTimeStr}.getTime() - h.Assert(t, testTime == asgLifecycleTime, "RFC3339 should be parsed correctly from event") + h.Assert(t, testTime.Equal(asgLifecycleTime), "RFC3339 should be parsed correctly from event") } func TestGetTime_Empty(t *testing.T) { diff --git a/pkg/monitor/sqsevent/sqs-retryer_test.go b/pkg/monitor/sqsevent/sqs-retryer_test.go index d097f930..785527e7 100644 --- a/pkg/monitor/sqsevent/sqs-retryer_test.go +++ b/pkg/monitor/sqsevent/sqs-retryer_test.go @@ -103,10 +103,10 @@ func getSqsRetryer(t *testing.T) sqsevent.SqsRetryer { h.Ok(t, err) sqsClient := sqsevent.GetSqsClient(sess) - h.Assert(t, sqsClient.Client.Config.Region != nil, "Region should not be nil") - h.Equals(t, "us-east-1", *sqsClient.Client.Config.Region) + h.Assert(t, sqsClient.Config.Region != nil, "Region should not be nil") + h.Equals(t, "us-east-1", *sqsClient.Config.Region) - retryer, ok := sqsClient.Client.Config.Retryer.(sqsevent.SqsRetryer) + retryer, ok := sqsClient.Config.Retryer.(sqsevent.SqsRetryer) h.Assert(t, ok, "Retryer should be of type SqsRetryer") return retryer } diff --git a/pkg/node/node.go b/pkg/node/node.go index b80d6ebf..48c5bd75 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -327,7 +327,7 @@ func (n Node) addLabel(nodeName string, key string, value string, skipExisting b return err } if skipExisting { - _, ok := node.ObjectMeta.Labels[key] + _, ok := node.Labels[key] if ok { return nil } @@ -394,7 +394,7 @@ func (n Node) removeLabelIfValueMatches(nodeName string, key string, matchValue if err != nil { return err } - val, ok := node.ObjectMeta.Labels[key] + val, ok := node.Labels[key] if !ok || val == matchValue { return nil } @@ -763,8 +763,8 @@ func getDrainHelper(nthConfig config.Config, clientset *kubernetes.Clientset) (* } func jsonPatchEscape(value string) string { - value = strings.Replace(value, "~", "~0", -1) - return strings.Replace(value, "/", "~1", -1) + value = strings.ReplaceAll(value, "~", "~0") + return strings.ReplaceAll(value, "/", "~1") } func getTaintEffect(effect string) corev1.TaintEffect { diff --git a/pkg/node/node_internal_test.go b/pkg/node/node_internal_test.go index 9f917cd2..e34fee6d 100644 --- a/pkg/node/node_internal_test.go +++ b/pkg/node/node_internal_test.go @@ -104,7 +104,7 @@ func TestUncordonIfRebootedSystemNotRestarted(t *testing.T) { h.Ok(t, err) tNode := getNode(t, getTestDrainHelper(client), getUptimeFromFile(testFile)) err = tNode.UncordonIfRebooted(nodeName) - os.Remove(testFile) + _ = os.Remove(testFile) h.Ok(t, err) } @@ -128,7 +128,7 @@ func TestUncordonIfRebootedFailureToRemoveLabel(t *testing.T) { h.Ok(t, err) tNode := getNode(t, getTestDrainHelper(client), getUptimeFromFile(testFile)) err = tNode.UncordonIfRebooted(nodeName) - os.Remove(testFile) + _ = os.Remove(testFile) h.Assert(t, err != nil, "Failed to return error on UncordonIfReboted failure remove NTH Label") } @@ -153,7 +153,7 @@ func TestUncordonIfRebootedFailureSuccess(t *testing.T) { h.Ok(t, err) tNode := getNode(t, getTestDrainHelper(client), getUptimeFromFile(testFile)) err = tNode.UncordonIfRebooted(nodeName) - os.Remove(testFile) + _ = os.Remove(testFile) h.Ok(t, err) } diff --git a/pkg/node/node_test.go b/pkg/node/node_test.go index 052772a6..bb07f4b1 100644 --- a/pkg/node/node_test.go +++ b/pkg/node/node_test.go @@ -27,7 +27,6 @@ import ( "github.com/aws/aws-node-termination-handler/pkg/node" h "github.com/aws/aws-node-termination-handler/pkg/test" "github.com/aws/aws-node-termination-handler/pkg/uptime" - corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" @@ -470,8 +469,8 @@ func TestFilterOutDaemonSetPods(t *testing.T) { tNode, err := newNode(config.Config{IgnoreDaemonSets: true}, fake.NewSimpleClientset()) h.Ok(t, err) - mockPodList := &corev1.PodList{ - Items: []corev1.Pod{ + mockPodList := &v1.PodList{ + Items: []v1.Pod{ { ObjectMeta: metav1.ObjectMeta{ Name: "mock-daemon-pod", @@ -530,7 +529,7 @@ func TestTaintOutOfService(t *testing.T) { expectedTaint := v1.Taint{ Key: outOfServiceTaintKey, Value: outOfServiceTaintValue, - Effect: corev1.TaintEffectNoExecute, + Effect: v1.TaintEffectNoExecute, } for _, taint := range updatedNode.Spec.Taints { if taint.Key == expectedTaint.Key && diff --git a/pkg/observability/opentelemetry_test.go b/pkg/observability/opentelemetry_test.go index cf07f5e3..66db6e32 100644 --- a/pkg/observability/opentelemetry_test.go +++ b/pkg/observability/opentelemetry_test.go @@ -225,11 +225,11 @@ func TestServeMetrics(t *testing.T) { if err != nil { t.Errorf("server is not listening on port %d: %v", mockDefaultPort, err) } - conn.Close() + _ = conn.Close() conn, err = net.DialTimeout("tcp", fmt.Sprintf("localhost:%d", mockClosedPort), time.Second) if err == nil { - conn.Close() + _ = conn.Close() t.Errorf("server should not be listening on port %d: %v", mockClosedPort, err) } } diff --git a/pkg/test/helpers.go b/pkg/test/helpers.go index 74fcf26a..bb4a5bfe 100644 --- a/pkg/test/helpers.go +++ b/pkg/test/helpers.go @@ -61,7 +61,7 @@ func Equals(tb testing.TB, exp, act interface{}) { // TimeWithinRange fails the test if act is not after lowerBound or not before upperBound func TimeWithinRange(tb testing.TB, act time.Time, lowerBound time.Time, upperBound time.Time) { - if !(act.After(lowerBound) && act.Before(upperBound)) { + if !act.After(lowerBound) || !act.Before(upperBound) { _, file, line, _ := runtime.Caller(1) fmt.Printf("\033[31m%s:%d:\n\n\tlower bound: %#v\n\n\tgot: %#v\n\n\tupper bound: %#v\033[39m\n\n", filepath.Base(file), line, lowerBound, act, upperBound) tb.FailNow() diff --git a/pkg/uptime/common_test.go b/pkg/uptime/common_test.go index 23fad24d..2cc07d59 100644 --- a/pkg/uptime/common_test.go +++ b/pkg/uptime/common_test.go @@ -28,7 +28,7 @@ func TestUptimeFromFileSuccess(t *testing.T) { h.Ok(t, err) value, err := UptimeFromFile(testFile) - os.Remove(testFile) + _ = os.Remove(testFile) h.Ok(t, err) h.Equals(t, int64(350735), value) } @@ -44,6 +44,6 @@ func TestUptimeFromFileBadData(t *testing.T) { h.Ok(t, err) _, err = UptimeFromFile(testFile) - os.Remove(testFile) + _ = os.Remove(testFile) h.Assert(t, err != nil, "Failed to return error for int64 parse") } diff --git a/pkg/webhook/webhook.go b/pkg/webhook/webhook.go index 4c6ced4d..82771023 100644 --- a/pkg/webhook/webhook.go +++ b/pkg/webhook/webhook.go @@ -118,7 +118,7 @@ func Post(additionalInfo ec2metadata.NodeMetadata, event *monitor.InterruptionEv return } - defer response.Body.Close() + defer func() { _ = response.Body.Close() }() if response.StatusCode < 200 || response.StatusCode > 299 { log.Warn().Int("status_code", response.StatusCode).Msg("Webhook Error: Received Non-Successful Status Code") @@ -139,7 +139,7 @@ func ValidateWebhookConfig(nthConfig config.Config) error { if nthConfig.WebhookTemplateFile != "" { content, err := os.ReadFile(nthConfig.WebhookTemplateFile) if err != nil { - return fmt.Errorf("Webhook Error: Could not read template file %w", err) + return fmt.Errorf("webhook error: could not read template file %w", err) } webhookTemplateContent = string(content) } else { @@ -148,13 +148,13 @@ func ValidateWebhookConfig(nthConfig config.Config) error { webhookTemplate, err := template.New("message").Funcs(sprig.TxtFuncMap()).Parse(webhookTemplateContent) if err != nil { - return fmt.Errorf("Unable to parse webhook template: %w", err) + return fmt.Errorf("unable to parse webhook template: %w", err) } var byteBuffer bytes.Buffer err = webhookTemplate.Execute(&byteBuffer, &combinedDrainData{}) if err != nil { - return fmt.Errorf("Unable to execute webhook template: %w", err) + return fmt.Errorf("unable to execute webhook template: %w", err) } return nil } diff --git a/pkg/webhook/webhook_test.go b/pkg/webhook/webhook_test.go index ecd073dd..423d2593 100644 --- a/pkg/webhook/webhook_test.go +++ b/pkg/webhook/webhook_test.go @@ -181,7 +181,7 @@ func TestPostHeaderParseFail(t *testing.T) { } func TestPostTimeout(t *testing.T) { - var requestCount int = 0 + var requestCount = 0 server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { requestCount++ time.Sleep(6 * time.Second) @@ -201,7 +201,7 @@ func TestPostTimeout(t *testing.T) { } func TestPostBadResponseCode(t *testing.T) { - var requestCount int = 0 + var requestCount = 0 server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { requestCount++ http.Error(rw, "404 page not found", http.StatusNotFound) diff --git a/test/webhook-test-proxy/Dockerfile b/test/webhook-test-proxy/Dockerfile index a0119541..9227505f 100644 --- a/test/webhook-test-proxy/Dockerfile +++ b/test/webhook-test-proxy/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.22-alpine as builder +FROM golang:1.25-alpine as builder ## GOLANG env ARG GOPROXY="https://proxy.golang.org|direct" diff --git a/test/webhook-test-proxy/Dockerfile.windows b/test/webhook-test-proxy/Dockerfile.windows index 5810b1cc..98eda76c 100644 --- a/test/webhook-test-proxy/Dockerfile.windows +++ b/test/webhook-test-proxy/Dockerfile.windows @@ -1,7 +1,7 @@ ARG WINDOWS_VERSION=1903 # Build the manager binary -FROM --platform=windows/amd64 golang:1.22 AS builder +FROM --platform=windows/amd64 golang:1.25 AS builder ## GOLANG env ENV GO111MODULE="on" CGO_ENABLED="0" GOOS="windows" GOARCH="amd64"