From ff1a30fe8dd4a0da38ddd34915b0be2210d39614 Mon Sep 17 00:00:00 2001 From: Seth Hoenig Date: Wed, 21 Sep 2022 14:53:25 -0500 Subject: [PATCH] cleanup more helper updates (#14638) * cleanup: refactor MapStringStringSliceValueSet to be cleaner * cleanup: replace SliceStringToSet with actual set * cleanup: replace SliceStringSubset with real set * cleanup: replace SliceStringContains with slices.Contains * cleanup: remove unused function SliceStringHasPrefix * cleanup: fixup StringHasPrefixInSlice doc string * cleanup: refactor SliceSetDisjoint to use real set * cleanup: replace CompareSliceSetString with SliceSetEq * cleanup: replace CompareMapStringString with maps.Equal * cleanup: replace CopyMapStringString with CopyMap * cleanup: replace CopyMapStringInterface with CopyMap * cleanup: fixup more CopyMapStringString and CopyMapStringInt * cleanup: replace CopySliceString with slices.Clone * cleanup: remove unused CopySliceInt * cleanup: refactor CopyMapStringSliceString to be generic as CopyMapOfSlice * cleanup: replace CopyMap with maps.Clone * cleanup: run go mod tidy --- .../taskrunner/artifact_hook_test.go | 8 +- .../taskrunner/logmon_hook_test.go | 4 +- client/allocrunner/taskrunner/state/state.go | 10 +- client/allocrunner/taskrunner/task_runner.go | 3 +- client/client.go | 3 +- client/config/config.go | 8 +- .../pluginmanager/csimanager/fingerprint.go | 4 +- .../checks/checkstore/shim.go | 6 +- .../serviceregistration/checks/client_test.go | 4 +- client/serviceregistration/checks/result.go | 4 +- .../service_registration.go | 6 +- client/state/db_mem.go | 4 +- command/agent/config.go | 9 +- command/agent/consul/catalog_testing.go | 9 +- command/agent/consul/connect.go | 4 +- command/agent/consul/service_client.go | 6 +- command/agent/job_endpoint.go | 23 +- command/alloc_status.go | 4 +- command/operator_debug.go | 6 +- e2e/consul/consul.go | 4 +- e2e/consul/namespaces.go | 2 +- go.mod | 2 +- go.sum | 6 +- helper/funcs.go | 302 ++---------------- helper/funcs_test.go | 113 ++----- nomad/consul.go | 5 +- nomad/job_endpoint.go | 9 +- nomad/job_endpoint_hook_connect.go | 4 +- nomad/job_endpoint_hook_vault.go | 5 +- nomad/job_endpoint_hooks.go | 2 +- nomad/structs/config/audit.go | 8 +- nomad/structs/csi.go | 11 +- nomad/structs/funcs.go | 20 +- nomad/structs/network.go | 6 +- nomad/structs/node.go | 9 +- nomad/structs/service_registration.go | 5 +- nomad/structs/services.go | 55 ++-- nomad/structs/structs.go | 55 ++-- plugins/csi/client.go | 4 +- plugins/drivers/driver.go | 6 +- scheduler/generic_sched_test.go | 4 +- scheduler/util.go | 6 +- 42 files changed, 239 insertions(+), 529 deletions(-) diff --git a/client/allocrunner/taskrunner/artifact_hook_test.go b/client/allocrunner/taskrunner/artifact_hook_test.go index 1bf950616..92e28d104 100644 --- a/client/allocrunner/taskrunner/artifact_hook_test.go +++ b/client/allocrunner/taskrunner/artifact_hook_test.go @@ -16,10 +16,10 @@ import ( "github.com/hashicorp/nomad/client/allocrunner/interfaces" "github.com/hashicorp/nomad/client/allocrunner/taskrunner/getter" "github.com/hashicorp/nomad/client/taskenv" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/helper/testlog" "github.com/hashicorp/nomad/nomad/structs" "github.com/stretchr/testify/require" + "golang.org/x/exp/maps" ) // Statically assert the artifact hook implements the expected interface @@ -126,7 +126,7 @@ func TestTaskRunner_ArtifactHook_PartialDone(t *testing.T) { require.NoError(t, ioutil.WriteFile(file2, []byte{'1'}, 0644)) // Mock TaskRunner by copying state from resp to req and reset resp. - req.PreviousState = helper.CopyMapStringString(resp.State) + req.PreviousState = maps.Clone(resp.State) resp = interfaces.TaskPrestartResponse{} @@ -146,7 +146,7 @@ func TestTaskRunner_ArtifactHook_PartialDone(t *testing.T) { // Stop the test server entirely and assert that re-running works ts.Close() - req.PreviousState = helper.CopyMapStringString(resp.State) + req.PreviousState = maps.Clone(resp.State) resp = interfaces.TaskPrestartResponse{} err = artifactHook.Prestart(context.Background(), req, &resp) require.NoError(t, err) @@ -315,7 +315,7 @@ func TestTaskRunner_ArtifactHook_ConcurrentDownloadFailure(t *testing.T) { require.NoError(t, ioutil.WriteFile(file0, []byte{'0'}, 0644)) // Mock TaskRunner by copying state from resp to req and reset resp. - req.PreviousState = helper.CopyMapStringString(resp.State) + req.PreviousState = maps.Clone(resp.State) resp = interfaces.TaskPrestartResponse{} diff --git a/client/allocrunner/taskrunner/logmon_hook_test.go b/client/allocrunner/taskrunner/logmon_hook_test.go index a3e652443..bf5f9e7f0 100644 --- a/client/allocrunner/taskrunner/logmon_hook_test.go +++ b/client/allocrunner/taskrunner/logmon_hook_test.go @@ -9,11 +9,11 @@ import ( plugin "github.com/hashicorp/go-plugin" "github.com/hashicorp/nomad/ci" "github.com/hashicorp/nomad/client/allocrunner/interfaces" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/helper/testlog" "github.com/hashicorp/nomad/nomad/mock" pstructs "github.com/hashicorp/nomad/plugins/shared/structs" "github.com/stretchr/testify/require" + "golang.org/x/exp/maps" ) // Statically assert the logmon hook implements the expected interfaces @@ -96,7 +96,7 @@ func TestTaskRunner_LogmonHook_StartStop(t *testing.T) { // Running stop should shutdown logmon stopReq := interfaces.TaskStopRequest{ - ExistingState: helper.CopyMapStringString(resp.State), + ExistingState: maps.Clone(resp.State), } require.NoError(t, hook.Stop(context.Background(), &stopReq, nil)) } diff --git a/client/allocrunner/taskrunner/state/state.go b/client/allocrunner/taskrunner/state/state.go index a4bc26b0f..cda144003 100644 --- a/client/allocrunner/taskrunner/state/state.go +++ b/client/allocrunner/taskrunner/state/state.go @@ -1,8 +1,8 @@ package state import ( - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/plugins/drivers" + "golang.org/x/exp/maps" ) // LocalState is Task state which is persisted for use when restarting Nomad @@ -89,8 +89,8 @@ func (h *HookState) Copy() *HookState { c := new(HookState) *c = *h - c.Data = helper.CopyMapStringString(h.Data) - c.Env = helper.CopyMapStringString(h.Env) + c.Data = maps.Clone(h.Data) + c.Env = maps.Clone(h.Env) return c } @@ -103,9 +103,9 @@ func (h *HookState) Equal(o *HookState) bool { return false } - if !helper.CompareMapStringString(h.Data, o.Data) { + if !maps.Equal(h.Data, o.Data) { return false } - return helper.CompareMapStringString(h.Env, o.Env) + return maps.Equal(h.Env, o.Env) } diff --git a/client/allocrunner/taskrunner/task_runner.go b/client/allocrunner/taskrunner/task_runner.go index 445cf0440..664c2bf16 100644 --- a/client/allocrunner/taskrunner/task_runner.go +++ b/client/allocrunner/taskrunner/task_runner.go @@ -9,6 +9,7 @@ import ( "time" "github.com/hashicorp/nomad/client/lib/cgutil" + "golang.org/x/exp/slices" metrics "github.com/armon/go-metrics" log "github.com/hashicorp/go-hclog" @@ -1473,7 +1474,7 @@ func (tr *TaskRunner) setGaugeForMemory(ru *cstructs.TaskResourceUsage) { ms := ru.ResourceUsage.MemoryStats publishMetric := func(v uint64, reported, measured string) { - if v != 0 || helper.SliceStringContains(ms.Measured, measured) { + if v != 0 || slices.Contains(ms.Measured, measured) { metrics.SetGaugeWithLabels([]string{"client", "allocs", "memory", reported}, float32(v), tr.baseLabels) } diff --git a/client/client.go b/client/client.go index cfe8fcd6c..9797d428b 100644 --- a/client/client.go +++ b/client/client.go @@ -58,6 +58,7 @@ import ( "github.com/hashicorp/nomad/plugins/drivers" vaultapi "github.com/hashicorp/vault/api" "github.com/shirou/gopsutil/v3/host" + "golang.org/x/exp/maps" ) const ( @@ -2740,7 +2741,7 @@ func (c *Client) deriveSIToken(alloc *structs.Allocation, taskNames []string) (m // https://www.consul.io/api/acl/tokens.html#read-a-token // https://www.consul.io/docs/internals/security.html - m := helper.CopyMapStringString(resp.Tokens) + m := maps.Clone(resp.Tokens) return m, nil } diff --git a/client/config/config.go b/client/config/config.go index 9fde99100..4c6a9fc9f 100644 --- a/client/config/config.go +++ b/client/config/config.go @@ -13,11 +13,11 @@ import ( "github.com/hashicorp/consul-template/config" "github.com/hashicorp/nomad/client/lib/cgutil" "github.com/hashicorp/nomad/command/agent/host" + "golang.org/x/exp/maps" "golang.org/x/exp/slices" log "github.com/hashicorp/go-hclog" "github.com/hashicorp/nomad/client/state" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/helper/bufconndialer" "github.com/hashicorp/nomad/helper/pluginutils/loader" "github.com/hashicorp/nomad/helper/pointer" @@ -379,7 +379,7 @@ func (c *ClientTemplateConfig) Copy() *ClientTemplateConfig { *nc = *c if len(c.FunctionDenylist) > 0 { - nc.FunctionDenylist = helper.CopySliceString(nc.FunctionDenylist) + nc.FunctionDenylist = slices.Clone(nc.FunctionDenylist) } else if c.FunctionDenylist != nil { // Explicitly no functions denied (which is different than nil) nc.FunctionDenylist = []string{} @@ -705,8 +705,8 @@ func (c *Config) Copy() *Config { nc := *c nc.Node = nc.Node.Copy() - nc.Servers = helper.CopySliceString(nc.Servers) - nc.Options = helper.CopyMapStringString(nc.Options) + nc.Servers = slices.Clone(nc.Servers) + nc.Options = maps.Clone(nc.Options) nc.HostVolumes = structs.CopyMapStringClientHostVolumeConfig(nc.HostVolumes) nc.ConsulConfig = c.ConsulConfig.Copy() nc.VaultConfig = c.VaultConfig.Copy() diff --git a/client/pluginmanager/csimanager/fingerprint.go b/client/pluginmanager/csimanager/fingerprint.go index 981bb63c6..db10aac98 100644 --- a/client/pluginmanager/csimanager/fingerprint.go +++ b/client/pluginmanager/csimanager/fingerprint.go @@ -6,9 +6,9 @@ import ( "github.com/hashicorp/go-hclog" "github.com/hashicorp/nomad/client/dynamicplugins" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/nomad/structs" "github.com/hashicorp/nomad/plugins/csi" + "golang.org/x/exp/maps" ) type pluginFingerprinter struct { @@ -181,6 +181,6 @@ func structCSITopologyFromCSITopology(a *csi.Topology) *structs.CSITopology { } return &structs.CSITopology{ - Segments: helper.CopyMapStringString(a.Segments), + Segments: maps.Clone(a.Segments), } } diff --git a/client/serviceregistration/checks/checkstore/shim.go b/client/serviceregistration/checks/checkstore/shim.go index 33cbb1d92..0a6a64a2d 100644 --- a/client/serviceregistration/checks/checkstore/shim.go +++ b/client/serviceregistration/checks/checkstore/shim.go @@ -6,8 +6,8 @@ import ( "github.com/hashicorp/go-hclog" "github.com/hashicorp/nomad/client/serviceregistration/checks" "github.com/hashicorp/nomad/client/state" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/nomad/structs" + "golang.org/x/exp/maps" "golang.org/x/exp/slices" ) @@ -67,7 +67,7 @@ func (s *shim) restore() { } for id, m := range results { - s.current[id] = helper.CopyMap(m) + s.current[id] = maps.Clone(m) } } @@ -114,7 +114,7 @@ func (s *shim) List(allocID string) map[structs.CheckID]*structs.CheckQueryResul return nil } - return helper.CopyMap(m) + return maps.Clone(m) } func (s *shim) Purge(allocID string) error { diff --git a/client/serviceregistration/checks/client_test.go b/client/serviceregistration/checks/client_test.go index 2553bb9ce..7b7b76e68 100644 --- a/client/serviceregistration/checks/client_test.go +++ b/client/serviceregistration/checks/client_test.go @@ -12,12 +12,12 @@ import ( "time" "github.com/hashicorp/nomad/ci" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/helper/freeport" "github.com/hashicorp/nomad/helper/testlog" "github.com/hashicorp/nomad/nomad/mock" "github.com/hashicorp/nomad/nomad/structs" "github.com/shoenig/test/must" + "golang.org/x/exp/maps" "oss.indeed.com/go/libtime/libtimetest" ) @@ -220,7 +220,7 @@ func TestChecker_Do_HTTP_extras(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { method = r.Method body, _ = io.ReadAll(r.Body) - headers = helper.CopyMap(r.Header) + headers = maps.Clone(r.Header) w.WriteHeader(http.StatusOK) })) defer ts.Close() diff --git a/client/serviceregistration/checks/result.go b/client/serviceregistration/checks/result.go index 5b4c359bf..f7813288f 100644 --- a/client/serviceregistration/checks/result.go +++ b/client/serviceregistration/checks/result.go @@ -4,8 +4,8 @@ import ( "net/http" "time" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/nomad/structs" + "golang.org/x/exp/maps" ) // GetCheckQuery extracts the needed info from c to actually execute the check. @@ -23,7 +23,7 @@ func GetCheckQuery(c *structs.ServiceCheck) *Query { Protocol: protocol, Path: c.Path, Method: c.Method, - Headers: helper.CopyMap(c.Header), + Headers: maps.Clone(c.Header), Body: c.Body, } } diff --git a/client/serviceregistration/service_registration.go b/client/serviceregistration/service_registration.go index 2a76399b7..805a22729 100644 --- a/client/serviceregistration/service_registration.go +++ b/client/serviceregistration/service_registration.go @@ -4,8 +4,8 @@ import ( "context" "github.com/hashicorp/consul/api" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/nomad/structs" + "golang.org/x/exp/maps" ) // Handler is the interface the Nomad Client uses to register, update and @@ -152,7 +152,7 @@ func (s *ServiceRegistration) copy() *ServiceRegistration { // external fields. return &ServiceRegistration{ ServiceID: s.ServiceID, - CheckIDs: helper.CopyMapStringStruct(s.CheckIDs), - CheckOnUpdate: helper.CopyMapStringString(s.CheckOnUpdate), + CheckIDs: maps.Clone(s.CheckIDs), + CheckOnUpdate: maps.Clone(s.CheckOnUpdate), } } diff --git a/client/state/db_mem.go b/client/state/db_mem.go index e22e8726e..284fc3f41 100644 --- a/client/state/db_mem.go +++ b/client/state/db_mem.go @@ -9,8 +9,8 @@ import ( "github.com/hashicorp/nomad/client/dynamicplugins" driverstate "github.com/hashicorp/nomad/client/pluginmanager/drivermanager/state" "github.com/hashicorp/nomad/client/serviceregistration/checks" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/nomad/structs" + "golang.org/x/exp/maps" ) // MemDB implements a StateDB that stores data in memory and should only be @@ -248,7 +248,7 @@ func (m *MemDB) PutCheckResult(allocID string, qr *structs.CheckQueryResult) err func (m *MemDB) GetCheckResults() (checks.ClientResults, error) { m.mu.Lock() defer m.mu.Unlock() - return helper.CopyMap(m.checks), nil + return maps.Clone(m.checks), nil } func (m *MemDB) DeleteCheckResults(allocID string, checkIDs []structs.CheckID) error { diff --git a/command/agent/config.go b/command/agent/config.go index 20da9d727..e69b827d8 100644 --- a/command/agent/config.go +++ b/command/agent/config.go @@ -27,6 +27,7 @@ import ( "github.com/hashicorp/nomad/nomad/structs" "github.com/hashicorp/nomad/nomad/structs/config" "github.com/hashicorp/nomad/version" + "golang.org/x/exp/maps" "golang.org/x/exp/slices" ) @@ -341,9 +342,9 @@ func (c *ClientConfig) Copy() *ClientConfig { nc := *c nc.Servers = slices.Clone(c.Servers) - nc.Options = helper.CopyMap(c.Options) - nc.Meta = helper.CopyMap(c.Meta) - nc.ChrootEnv = helper.CopyMap(c.ChrootEnv) + nc.Options = maps.Clone(c.Options) + nc.Meta = maps.Clone(c.Meta) + nc.ChrootEnv = maps.Clone(c.ChrootEnv) nc.Reserved = c.Reserved.Copy() nc.NoHostUUID = pointer.Copy(c.NoHostUUID) nc.TemplateConfig = c.TemplateConfig.Copy() @@ -1513,7 +1514,7 @@ func (c *Config) Copy() *Config { nc.Version = c.Version.Copy() nc.Files = slices.Clone(c.Files) nc.TLSConfig = c.TLSConfig.Copy() - nc.HTTPAPIResponseHeaders = helper.CopyMap(c.HTTPAPIResponseHeaders) + nc.HTTPAPIResponseHeaders = maps.Clone(c.HTTPAPIResponseHeaders) nc.Sentinel = c.Sentinel.Copy() nc.Autopilot = c.Autopilot.Copy() nc.Plugins = helper.CopySlice(c.Plugins) diff --git a/command/agent/consul/catalog_testing.go b/command/agent/consul/catalog_testing.go index 69eb78f6e..0a2a971e8 100644 --- a/command/agent/consul/catalog_testing.go +++ b/command/agent/consul/catalog_testing.go @@ -7,7 +7,8 @@ import ( "github.com/hashicorp/consul/api" "github.com/hashicorp/go-hclog" - "github.com/hashicorp/nomad/helper" + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" ) // MockNamespaces is a mock implementation of NamespaceAPI. @@ -20,8 +21,8 @@ var _ NamespaceAPI = (*MockNamespaces)(nil) // NewMockNamespaces creates a MockNamespaces with the given namespaces, and // will automatically add the "default" namespace if not included. func NewMockNamespaces(namespaces []string) *MockNamespaces { - list := helper.CopySliceString(namespaces) - if !helper.SliceStringContains(list, "default") { + list := slices.Clone(namespaces) + if !slices.Contains(list, "default") { list = append(list, "default") } sort.Strings(list) @@ -213,7 +214,7 @@ func (c *MockAgent) ServicesWithFilterOpts(_ string, q *api.QueryOptions) (map[s ID: v.ID, Service: v.Name, Tags: make([]string, len(v.Tags)), - Meta: helper.CopyMapStringString(v.Meta), + Meta: maps.Clone(v.Meta), Port: v.Port, Address: v.Address, EnableTagOverride: v.EnableTagOverride, diff --git a/command/agent/consul/connect.go b/command/agent/consul/connect.go index 5edbfab12..e30475bcb 100644 --- a/command/agent/consul/connect.go +++ b/command/agent/consul/connect.go @@ -7,8 +7,8 @@ import ( "strings" "github.com/hashicorp/consul/api" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/nomad/structs" + "golang.org/x/exp/slices" ) // newConnect creates a new Consul AgentServiceConnect struct based on a Nomad @@ -122,7 +122,7 @@ func connectSidecarRegistration(serviceID, allocID string, css *structs.ConsulSi } return &api.AgentServiceRegistration{ - Tags: helper.CopySliceString(css.Tags), + Tags: slices.Clone(css.Tags), Port: cMapping.Value, Address: cMapping.HostIP, Proxy: proxy, diff --git a/command/agent/consul/service_client.go b/command/agent/consul/service_client.go index 22dfd9f05..bea559594 100644 --- a/command/agent/consul/service_client.go +++ b/command/agent/consul/service_client.go @@ -17,9 +17,9 @@ import ( "github.com/hashicorp/consul/api" "github.com/hashicorp/go-hclog" "github.com/hashicorp/nomad/client/serviceregistration" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/helper/envoy" "github.com/hashicorp/nomad/nomad/structs" + "golang.org/x/exp/slices" ) const ( @@ -183,12 +183,12 @@ func agentServiceUpdateRequired(reason syncReason, wanted *api.AgentServiceRegis // unchanged. func maybeTweakTags(wanted *api.AgentServiceRegistration, existing *api.AgentService, sidecar *api.AgentService) { if wanted.EnableTagOverride { - wanted.Tags = helper.CopySliceString(existing.Tags) + wanted.Tags = slices.Clone(existing.Tags) // If the service registration also defines a sidecar service, use the ETO // setting for the parent service to also apply to the sidecar. if wanted.Connect != nil && wanted.Connect.SidecarService != nil { if sidecar != nil { - wanted.Connect.SidecarService.Tags = helper.CopySliceString(sidecar.Tags) + wanted.Connect.SidecarService.Tags = slices.Clone(sidecar.Tags) } } } diff --git a/command/agent/job_endpoint.go b/command/agent/job_endpoint.go index 2fbd8f5d5..dc31ea6d5 100644 --- a/command/agent/job_endpoint.go +++ b/command/agent/job_endpoint.go @@ -9,10 +9,11 @@ import ( "github.com/golang/snappy" "github.com/hashicorp/nomad/acl" api "github.com/hashicorp/nomad/api" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/jobspec" "github.com/hashicorp/nomad/jobspec2" "github.com/hashicorp/nomad/nomad/structs" + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" ) // jobNotFoundErr is an error string which can be used as the return string @@ -1188,8 +1189,8 @@ func ApiTaskToStructsTask(job *structs.Job, group *structs.TaskGroup, structsTask.Artifacts = append(structsTask.Artifacts, &structs.TaskArtifact{ GetterSource: *ta.GetterSource, - GetterOptions: helper.CopyMapStringString(ta.GetterOptions), - GetterHeaders: helper.CopyMapStringString(ta.GetterHeaders), + GetterOptions: maps.Clone(ta.GetterOptions), + GetterHeaders: maps.Clone(ta.GetterHeaders), GetterMode: *ta.GetterMode, RelativeDest: *ta.RelativeDest, }) @@ -1392,9 +1393,9 @@ func ApiServicesToStructs(in []*api.Service, group bool) []*structs.Service { EnableTagOverride: s.EnableTagOverride, AddressMode: s.AddressMode, Address: s.Address, - Meta: helper.CopyMapStringString(s.Meta), - CanaryMeta: helper.CopyMapStringString(s.CanaryMeta), - TaggedAddresses: helper.CopyMapStringString(s.TaggedAddresses), + Meta: maps.Clone(s.Meta), + CanaryMeta: maps.Clone(s.CanaryMeta), + TaggedAddresses: maps.Clone(s.TaggedAddresses), OnUpdate: s.OnUpdate, Provider: s.Provider, } @@ -1500,7 +1501,7 @@ func apiConnectGatewayProxyToStructs(in *api.ConsulGatewayProxy) *structs.Consul EnvoyGatewayBindAddresses: bindAddresses, EnvoyGatewayNoDefaultBind: in.EnvoyGatewayNoDefaultBind, EnvoyDNSDiscoveryType: in.EnvoyDNSDiscoveryType, - Config: helper.CopyMapStringInterface(in.Config), + Config: maps.Clone(in.Config), } } @@ -1524,7 +1525,7 @@ func apiConnectGatewayTLSConfig(in *api.ConsulGatewayTLSConfig) *structs.ConsulG Enabled: in.Enabled, TLSMinVersion: in.TLSMinVersion, TLSMaxVersion: in.TLSMaxVersion, - CipherSuites: helper.CopySliceString(in.CipherSuites), + CipherSuites: slices.Clone(in.CipherSuites), } } @@ -1571,7 +1572,7 @@ func apiConnectIngressServiceToStructs(in *api.ConsulIngressService) *structs.Co return &structs.ConsulIngressService{ Name: in.Name, - Hosts: helper.CopySliceString(in.Hosts), + Hosts: slices.Clone(in.Hosts), } } @@ -1624,7 +1625,7 @@ func apiConnectSidecarServiceToStructs(in *api.ConsulSidecarService) *structs.Co } return &structs.ConsulSidecarService{ Port: in.Port, - Tags: helper.CopySliceString(in.Tags), + Tags: slices.Clone(in.Tags), Proxy: apiConnectSidecarServiceProxyToStructs(in.Proxy), DisableDefaultTCPCheck: in.DisableDefaultTCPCheck, } @@ -1639,7 +1640,7 @@ func apiConnectSidecarServiceProxyToStructs(in *api.ConsulProxy) *structs.Consul LocalServicePort: in.LocalServicePort, Upstreams: apiUpstreamsToStructs(in.Upstreams), Expose: apiConsulExposeConfigToStructs(in.ExposeConfig), - Config: helper.CopyMapStringInterface(in.Config), + Config: maps.Clone(in.Config), } } diff --git a/command/alloc_status.go b/command/alloc_status.go index 66f358986..39d7bb1cb 100644 --- a/command/alloc_status.go +++ b/command/alloc_status.go @@ -10,10 +10,10 @@ import ( "github.com/dustin/go-humanize" "github.com/posener/complete" + "golang.org/x/exp/slices" "github.com/hashicorp/nomad/api" "github.com/hashicorp/nomad/api/contexts" - "github.com/hashicorp/nomad/helper" ) type AllocStatusCommand struct { @@ -623,7 +623,7 @@ func (c *AllocStatusCommand) outputTaskResources(alloc *api.Allocation, task str // Nomad uses RSS as the top-level metric to report, for historical reasons, // but it's not always measured (e.g. with cgroup-v2) usage := ms.RSS - if usage == 0 && !helper.SliceStringContains(ms.Measured, "RSS") { + if usage == 0 && !slices.Contains(ms.Measured, "RSS") { usage = ms.Usage } memUsage = fmt.Sprintf("%v/%v", humanize.IBytes(usage), memUsage) diff --git a/command/operator_debug.go b/command/operator_debug.go index 7966f7574..8916517e6 100644 --- a/command/operator_debug.go +++ b/command/operator_debug.go @@ -30,6 +30,8 @@ import ( "github.com/hashicorp/nomad/helper/escapingfs" "github.com/hashicorp/nomad/version" "github.com/posener/complete" + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" ) type OperatorDebugCommand struct { @@ -334,7 +336,7 @@ func ServerPredictor(factory ApiClientFactory) complete.Predictor { func (c *OperatorDebugCommand) queryOpts() *api.QueryOptions { qo := new(api.QueryOptions) *qo = *c.opts - qo.Params = helper.CopyMapStringString(c.opts.Params) + qo.Params = maps.Clone(c.opts.Params) return qo } @@ -1527,7 +1529,7 @@ func filterServerMembers(serverMembers *api.ServerMembers, serverIDs string, reg // "leader" is a special case which Nomad handles in the API. If "leader" // appears in serverIDs, add it to membersFound and remove it from the list // so that it isn't processed by the range loop - if helper.SliceStringContains(prefixes, "leader") { + if slices.Contains(prefixes, "leader") { membersFound = append(membersFound, "leader") helper.RemoveEqualFold(&prefixes, "leader") } diff --git a/e2e/consul/consul.go b/e2e/consul/consul.go index a277f81c8..9dcf59e2d 100644 --- a/e2e/consul/consul.go +++ b/e2e/consul/consul.go @@ -212,7 +212,7 @@ func (tc *ConsulE2ETest) TestCanaryInplaceUpgrades(f *framework.F) { return false, err } for _, s := range consulServices { - if helper.CompareSliceSetString([]string{"canary", "foo"}, s.ServiceTags) { + if helper.SliceSetEq([]string{"canary", "foo"}, s.ServiceTags) { return true, nil } } @@ -247,7 +247,7 @@ func (tc *ConsulE2ETest) TestCanaryInplaceUpgrades(f *framework.F) { return false, err } for _, s := range consulServices { - if !helper.CompareSliceSetString(expected, s.ServiceTags) { + if !helper.SliceSetEq(expected, s.ServiceTags) { return false, fmt.Errorf("expected %#v Consul tags but found %#v", expected, s.ServiceTags) } diff --git a/e2e/consul/namespaces.go b/e2e/consul/namespaces.go index 9429ecd6f..fc8cda8ce 100644 --- a/e2e/consul/namespaces.go +++ b/e2e/consul/namespaces.go @@ -91,7 +91,7 @@ func (tc *ConsulNamespacesE2ETest) AfterAll(f *framework.F) { func (tc *ConsulNamespacesE2ETest) TestNamespacesExist(f *framework.F) { // make sure our namespaces exist + default namespaces := e2eutil.ListConsulNamespaces(f.T(), tc.Consul()) - require.True(f.T(), helper.CompareSliceSetString(namespaces, append(consulNamespaces, "default"))) + require.True(f.T(), helper.SliceSetEq(namespaces, append(consulNamespaces, "default"))) } func (tc *ConsulNamespacesE2ETest) testConsulRegisterGroupServices(f *framework.F, token, nsA, nsB, nsC, nsZ string) { diff --git a/go.mod b/go.mod index 3c78b5b4c..df469986d 100644 --- a/go.mod +++ b/go.mod @@ -119,7 +119,7 @@ require ( go.etcd.io/bbolt v1.3.6 go.uber.org/goleak v1.1.12 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d - golang.org/x/exp v0.0.0-20220609121020-a51bd0440498 + golang.org/x/exp v0.0.0-20220921164117-439092de6870 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20220803195053-6e608f9ce704 golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 diff --git a/go.sum b/go.sum index 6cf4e9064..f21668e42 100644 --- a/go.sum +++ b/go.sum @@ -1339,8 +1339,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220609121020-a51bd0440498 h1:TF0FvLUGEq/8wOt/9AV1nj6D4ViZGUIGCMQfCv7VRXY= -golang.org/x/exp v0.0.0-20220609121020-a51bd0440498/go.mod h1:yh0Ynu2b5ZUe3MQfp2nM0ecK7wsgouWTDN0FNeJuIys= +golang.org/x/exp v0.0.0-20220921164117-439092de6870 h1:j8b6j9gzSigH28O5SjSpQSSh9lFd6f5D/q0aHjNTulc= +golang.org/x/exp v0.0.0-20220921164117-439092de6870/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1670,7 +1670,7 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/helper/funcs.go b/helper/funcs.go index ad640fd17..b699afd61 100644 --- a/helper/funcs.go +++ b/helper/funcs.go @@ -15,6 +15,8 @@ import ( "github.com/hashicorp/go-set" "github.com/hashicorp/hcl/hcl/ast" "golang.org/x/exp/constraints" + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" ) // validUUID is used to check if a given string looks like a UUID @@ -92,82 +94,28 @@ func Max[T constraints.Ordered](a, b T) T { return b } -// MapStringStringSliceValueSet returns the set of values in a map[string][]string -func MapStringStringSliceValueSet(m map[string][]string) []string { - set := make(map[string]struct{}) +// UniqueMapSliceValues returns the union of values from each slice in a map[K][]V. +func UniqueMapSliceValues[K, V comparable](m map[K][]V) []V { + s := set.New[V](0) for _, slice := range m { - for _, v := range slice { - set[v] = struct{}{} - } + s.InsertAll(slice) } - - flat := make([]string, 0, len(set)) - for k := range set { - flat = append(flat, k) - } - return flat + return s.List() } -func SliceStringToSet(s []string) map[string]struct{} { - m := make(map[string]struct{}, (len(s)+1)/2) - for _, k := range s { - m[k] = struct{}{} - } - return m -} - -func SetToSliceString(set map[string]struct{}) []string { - flattened := make([]string, 0, len(set)) - for x := range set { - flattened = append(flattened, x) - } - return flattened -} - -// SliceStringIsSubset returns whether the smaller set of strings is a subset of -// the larger. If the smaller slice is not a subset, the offending elements are +// IsSubset returns whether the smaller set of items is a subset of +// the larger. If the smaller set is not a subset, the offending elements are // returned. -func SliceStringIsSubset(larger, smaller []string) (bool, []string) { - largerSet := make(map[string]struct{}, len(larger)) - for _, l := range larger { - largerSet[l] = struct{}{} +func IsSubset[T comparable](larger, smaller []T) (bool, []T) { + l := set.From(larger) + if l.ContainsAll(smaller) { + return true, nil } - - subset := true - var offending []string - for _, s := range smaller { - if _, ok := largerSet[s]; !ok { - subset = false - offending = append(offending, s) - } - } - - return subset, offending + s := set.From(smaller) + return false, s.Difference(l).List() } -// SliceStringContains returns whether item exists at least once in list. -// -// Deprecated; use slices.Contains instead. -func SliceStringContains(list []string, item string) bool { - for _, s := range list { - if s == item { - return true - } - } - return false -} - -// SliceStringHasPrefix returns true if any string in list starts with prefix -func SliceStringHasPrefix(list []string, prefix string) bool { - for _, s := range list { - if strings.HasPrefix(s, prefix) { - return true - } - } - return false -} - -// StringHasPrefixInSlice returns true if string starts with any prefix in list +// StringHasPrefixInSlice returns true if s starts with any prefix in list. func StringHasPrefixInSlice(s string, prefixes []string) bool { for _, prefix := range prefixes { if strings.HasPrefix(s, prefix) { @@ -177,100 +125,15 @@ func StringHasPrefixInSlice(s string, prefixes []string) bool { return false } -func SliceSetDisjoint(first, second []string) (bool, []string) { - contained := make(map[string]struct{}, len(first)) - for _, k := range first { - contained[k] = struct{}{} +// IsDisjoint returns whether first and second are disjoint sets, and the set of +// offending elements if not. +func IsDisjoint[T comparable](first, second []T) (bool, []T) { + f, s := set.From(first), set.From(second) + intersection := f.Intersect(s) + if intersection.Size() > 0 { + return false, intersection.List() } - - offending := make(map[string]struct{}) - for _, k := range second { - if _, ok := contained[k]; ok { - offending[k] = struct{}{} - } - } - - if len(offending) == 0 { - return true, nil - } - - flattened := make([]string, 0, len(offending)) - for k := range offending { - flattened = append(flattened, k) - } - return false, flattened -} - -// CompareSliceSetString returns true if the slices contain the same strings. -// Order is ignored. The slice may be copied but is never altered. The slice is -// assumed to be a set. Multiple instances of an entry are treated the same as -// a single instance. -func CompareSliceSetString(a, b []string) bool { - n := len(a) - if n != len(b) { - return false - } - - // Copy a into a map and compare b against it - amap := make(map[string]struct{}, n) - for i := range a { - amap[a[i]] = struct{}{} - } - - for i := range b { - if _, ok := amap[b[i]]; !ok { - return false - } - } - - return true -} - -// CompareMapStringString returns true if the maps are equivalent. A nil and -// empty map are considered not equal. -func CompareMapStringString(a, b map[string]string) bool { - if a == nil || b == nil { - return a == nil && b == nil - } - - if len(a) != len(b) { - return false - } - - for k, v := range a { - v2, ok := b[k] - if !ok { - return false - } - if v != v2 { - return false - } - } - - // Already compared all known values in a so only test that keys from b - // exist in a - for k := range b { - if _, ok := a[k]; !ok { - return false - } - } - - return true -} - -// CopyMap creates a copy of m. Struct values are not deep copies. -// -// If m is nil the return value is nil. -func CopyMap[M ~map[K]V, K comparable, V any](m M) M { - if m == nil { - return nil - } - - result := make(M, len(m)) - for k, v := range m { - result[k] = v - } - return result + return true, nil } // DeepCopyMap creates a copy of m by calling Copy() on each value. @@ -302,51 +165,6 @@ func CopySlice[S ~[]E, E Copyable[E]](s S) S { return result } -// CopyMapStringString creates a copy of m. -// -// Deprecated; use CopyMap instead. -func CopyMapStringString(m map[string]string) map[string]string { - if m == nil { - return nil - } - - c := make(map[string]string, len(m)) - for k, v := range m { - c[k] = v - } - return c -} - -// CopyMapStringStruct creates a copy of m. -// -// Deprecated; use CopyMap instead. -func CopyMapStringStruct(m map[string]struct{}) map[string]struct{} { - if m == nil { - return nil - } - - c := make(map[string]struct{}, len(m)) - for k := range m { - c[k] = struct{}{} - } - return c -} - -// CopyMapStringInterface creates a copy of m. -// -// Deprecated; use CopyMap instead. -func CopyMapStringInterface(m map[string]interface{}) map[string]interface{} { - if m == nil { - return nil - } - - c := make(map[string]interface{}, len(m)) - for k, v := range m { - c[k] = v - } - return c -} - // MergeMapStringString will merge two maps into one. If a duplicate key exists // the value in the second map will replace the value in the first map. If both // maps are empty or nil this returns an empty map. @@ -361,7 +179,7 @@ func MergeMapStringString(m map[string]string, n map[string]string) map[string]s return m } - result := CopyMapStringString(m) + result := maps.Clone(m) for k, v := range n { result[k] = v @@ -370,82 +188,20 @@ func MergeMapStringString(m map[string]string, n map[string]string) map[string]s return result } -// CopyMapStringInt creates a copy of m. -// -// Deprecated; use CopyMap instead. -func CopyMapStringInt(m map[string]int) map[string]int { +// CopyMapOfSlice creates a copy of m, making copies of each []V. +func CopyMapOfSlice[K comparable, V any](m map[K][]V) map[K][]V { l := len(m) if l == 0 { return nil } - c := make(map[string]int, l) + c := make(map[K][]V, l) for k, v := range m { - c[k] = v + c[k] = slices.Clone(v) } return c } -// CopyMapStringFloat64 creates a copy of m. -// -// Deprecated; use CopyMap instead. -func CopyMapStringFloat64(m map[string]float64) map[string]float64 { - l := len(m) - if l == 0 { - return nil - } - - c := make(map[string]float64, l) - for k, v := range m { - c[k] = v - } - return c -} - -// CopyMapStringSliceString creates a copy of m. -// -// todo: a deep value copy version of CopyMap. -func CopyMapStringSliceString(m map[string][]string) map[string][]string { - l := len(m) - if l == 0 { - return nil - } - - c := make(map[string][]string, l) - for k, v := range m { - c[k] = CopySliceString(v) - } - return c -} - -// CopySliceString creates a copy of s. -// -// Deprecated; use slices.Clone instead. -func CopySliceString(s []string) []string { - l := len(s) - if l == 0 { - return nil - } - - c := make([]string, l) - copy(c, s) - return c -} - -// CopySliceInt creates a copy of s. -// -// Deprecated; use slices.Clone instead. -func CopySliceInt(s []int) []int { - l := len(s) - if l == 0 { - return nil - } - - c := make([]int, l) - copy(c, s) - return c -} - // CleanEnvVar replaces all occurrences of illegal characters in an environment // variable with the specified byte. func CleanEnvVar(s string, r byte) string { diff --git a/helper/funcs_test.go b/helper/funcs_test.go index 7cf1fdab9..646d98d74 100644 --- a/helper/funcs_test.go +++ b/helper/funcs_test.go @@ -6,8 +6,10 @@ import ( "sort" "testing" + "github.com/hashicorp/go-set" "github.com/shoenig/test/must" "github.com/stretchr/testify/require" + "golang.org/x/exp/maps" ) func Test_Min(t *testing.T) { @@ -56,62 +58,35 @@ func Test_Max(t *testing.T) { }) } -func Test_CopyMap(t *testing.T) { - t.Run("nil", func(t *testing.T) { - var m map[string]int - result := CopyMap(m) - must.Nil(t, result) - }) - - t.Run("empty", func(t *testing.T) { - m := make(map[string]int, 10) - result := CopyMap(m) - must.MapEq(t, map[string]int{}, result) - }) - - t.Run("elements", func(t *testing.T) { - m := map[string]int{"a": 1, "b": 2} - result := CopyMap(m) - result["a"] = -1 - must.MapEq(t, map[string]int{"a": -1, "b": 2}, result) - must.MapEq(t, map[string]int{"a": 1, "b": 2}, m) // not modified - }) -} - -func TestSliceStringIsSubset(t *testing.T) { +func TestIsSubset(t *testing.T) { l := []string{"a", "b", "c"} s := []string{"d"} - sub, offending := SliceStringIsSubset(l, l[:1]) - if !sub || len(offending) != 0 { - t.Fatalf("bad %v %v", sub, offending) - } + sub, offending := IsSubset(l, l[:1]) + must.True(t, sub) + must.EmptySlice(t, offending) - sub, offending = SliceStringIsSubset(l, s) - if sub || len(offending) == 0 || offending[0] != "d" { - t.Fatalf("bad %v %v", sub, offending) - } + sub, offending = IsSubset(l, s) + must.False(t, sub) + must.Eq(t, []string{"d"}, offending) } -func TestSliceStringContains(t *testing.T) { - list := []string{"a", "b", "c"} - require.True(t, SliceStringContains(list, "a")) - require.True(t, SliceStringContains(list, "b")) - require.True(t, SliceStringContains(list, "c")) - require.False(t, SliceStringContains(list, "d")) -} - -func TestSliceStringHasPrefix(t *testing.T) { - list := []string{"alpha", "bravo", "charlie", "definitely", "most definitely"} - // At least one string in the slice above starts with the following test prefix strings - require.True(t, SliceStringHasPrefix(list, "a")) - require.True(t, SliceStringHasPrefix(list, "b")) - require.True(t, SliceStringHasPrefix(list, "c")) - require.True(t, SliceStringHasPrefix(list, "d")) - require.True(t, SliceStringHasPrefix(list, "mos")) - require.True(t, SliceStringHasPrefix(list, "def")) - require.False(t, SliceStringHasPrefix(list, "delta")) +func TestIsDisjoint(t *testing.T) { + t.Run("yes", func(t *testing.T) { + a := []string{"a", "b", "c"} + b := []string{"d", "f"} + dis, offending := IsDisjoint(a, b) + must.True(t, dis) + must.EmptySlice(t, offending) + }) + t.Run("no", func(t *testing.T) { + a := []string{"a", "b", "c", "d", "e"} + b := []string{"b", "c", "f", "g"} + dis, offending := IsDisjoint(a, b) + must.False(t, dis) + must.True(t, set.From(offending).EqualSlice(offending)) + }) } func TestStringHasPrefixInSlice(t *testing.T) { @@ -180,7 +155,7 @@ func TestCompareSliceSetString(t *testing.T) { for i, tc := range cases { tc := tc t.Run(fmt.Sprintf("case-%da", i), func(t *testing.T) { - if res := CompareSliceSetString(tc.A, tc.B); res != tc.Result { + if res := SliceSetEq(tc.A, tc.B); res != tc.Result { t.Fatalf("expected %t but CompareSliceSetString(%v, %v) -> %t", tc.Result, tc.A, tc.B, res, ) @@ -189,7 +164,7 @@ func TestCompareSliceSetString(t *testing.T) { // Function is commutative so compare B and A t.Run(fmt.Sprintf("case-%db", i), func(t *testing.T) { - if res := CompareSliceSetString(tc.B, tc.A); res != tc.Result { + if res := SliceSetEq(tc.B, tc.A); res != tc.Result { t.Fatalf("expected %t but CompareSliceSetString(%v, %v) -> %t", tc.Result, tc.B, tc.A, res, ) @@ -198,30 +173,17 @@ func TestCompareSliceSetString(t *testing.T) { } } -func TestMapStringStringSliceValueSet(t *testing.T) { +func TestUniqueMapSliceValues(t *testing.T) { m := map[string][]string{ "foo": {"1", "2"}, "bar": {"3"}, "baz": nil, } - act := MapStringStringSliceValueSet(m) + act := UniqueMapSliceValues(m) exp := []string{"1", "2", "3"} sort.Strings(act) - if !reflect.DeepEqual(act, exp) { - t.Fatalf("Bad; got %v; want %v", act, exp) - } -} - -func TestSetToSliceString(t *testing.T) { - set := map[string]struct{}{ - "foo": {}, - "bar": {}, - "baz": {}, - } - expect := []string{"foo", "bar", "baz"} - got := SetToSliceString(set) - require.ElementsMatch(t, expect, got) + must.Eq(t, exp, act) } func TestCopyMapStringSliceString(t *testing.T) { @@ -231,7 +193,7 @@ func TestCopyMapStringSliceString(t *testing.T) { "z": nil, } - c := CopyMapStringSliceString(m) + c := CopyMapOfSlice(m) if !reflect.DeepEqual(c, m) { t.Fatalf("%#v != %#v", m, c) } @@ -242,19 +204,6 @@ func TestCopyMapStringSliceString(t *testing.T) { } } -func TestCopyMapSliceInterface(t *testing.T) { - m := map[string]interface{}{ - "foo": "bar", - "baz": 2, - } - - c := CopyMapStringInterface(m) - require.True(t, reflect.DeepEqual(m, c)) - - m["foo"] = "zzz" - require.False(t, reflect.DeepEqual(m, c)) -} - func TestMergeMapStringString(t *testing.T) { type testCase struct { map1 map[string]string @@ -270,7 +219,7 @@ func TestMergeMapStringString(t *testing.T) { } for _, c := range cases { - if output := MergeMapStringString(c.map1, c.map2); !CompareMapStringString(output, c.expected) { + if output := MergeMapStringString(c.map1, c.map2); !maps.Equal(output, c.expected) { t.Errorf("MergeMapStringString(%q, %q) -> %q != %q", c.map1, c.map2, output, c.expected) } } diff --git a/nomad/consul.go b/nomad/consul.go index 7eac19ff8..e5fe3fe73 100644 --- a/nomad/consul.go +++ b/nomad/consul.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/nomad/command/agent/consul" "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/nomad/structs" + "golang.org/x/exp/slices" "golang.org/x/sync/errgroup" "golang.org/x/time/rate" ) @@ -593,7 +594,7 @@ func convertIngressCE(namespace, service string, entry *structs.ConsulIngressCon for _, s := range listener.Services { services = append(services, api.IngressService{ Name: s.Name, - Hosts: helper.CopySliceString(s.Hosts), + Hosts: slices.Clone(s.Hosts), }) } listeners = append(listeners, api.IngressListener{ @@ -608,7 +609,7 @@ func convertIngressCE(namespace, service string, entry *structs.ConsulIngressCon tls.Enabled = entry.TLS.Enabled tls.TLSMinVersion = entry.TLS.TLSMinVersion tls.TLSMaxVersion = entry.TLS.TLSMaxVersion - tls.CipherSuites = helper.CopySliceString(entry.TLS.CipherSuites) + tls.CipherSuites = slices.Clone(entry.TLS.CipherSuites) } return &api.IngressGatewayConfigEntry{ diff --git a/nomad/job_endpoint.go b/nomad/job_endpoint.go index 50ac74e54..bbb320222 100644 --- a/nomad/job_endpoint.go +++ b/nomad/job_endpoint.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-memdb" "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-set" "github.com/hashicorp/nomad/acl" "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/helper/pointer" @@ -2006,14 +2007,14 @@ func validateDispatchRequest(req *structs.JobDispatchRequest, job *structs.Job) keys[k] = struct{}{} } - required := helper.SliceStringToSet(job.ParameterizedJob.MetaRequired) - optional := helper.SliceStringToSet(job.ParameterizedJob.MetaOptional) + required := set.From(job.ParameterizedJob.MetaRequired) + optional := set.From(job.ParameterizedJob.MetaOptional) // Check the metadata key constraints are met unpermitted := make(map[string]struct{}) for k := range req.Meta { - _, req := required[k] - _, opt := optional[k] + req := required.Contains(k) + opt := optional.Contains(k) if !req && !opt { unpermitted[k] = struct{}{} } diff --git a/nomad/job_endpoint_hook_connect.go b/nomad/job_endpoint_hook_connect.go index 2af2d7199..728729e80 100644 --- a/nomad/job_endpoint_hook_connect.go +++ b/nomad/job_endpoint_hook_connect.go @@ -7,11 +7,11 @@ import ( "time" "github.com/hashicorp/nomad/client/taskenv" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/helper/envoy" "github.com/hashicorp/nomad/helper/pointer" "github.com/hashicorp/nomad/helper/uuid" "github.com/hashicorp/nomad/nomad/structs" + "golang.org/x/exp/slices" ) const ( @@ -583,7 +583,7 @@ func groupConnectGatewayValidate(g *structs.TaskGroup) error { } modes := []string{"bridge", "host"} - if !helper.SliceStringContains(modes, g.Networks[0].Mode) { + if !slices.Contains(modes, g.Networks[0].Mode) { return fmt.Errorf(`Consul Connect Gateway service requires Task Group with network mode of type "bridge" or "host"`) } diff --git a/nomad/job_endpoint_hook_vault.go b/nomad/job_endpoint_hook_vault.go index f92bbdd9f..74d47a6df 100644 --- a/nomad/job_endpoint_hook_vault.go +++ b/nomad/job_endpoint_hook_vault.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/nomad/structs" vapi "github.com/hashicorp/vault/api" + "golang.org/x/exp/slices" ) // jobVaultHook is an job registration admission controller for Vault blocks. @@ -79,11 +80,11 @@ func (jobVaultHook) validatePolicies( } // If we are given a root token it can access all policies - if helper.SliceStringContains(allowedPolicies, "root") { + if slices.Contains(allowedPolicies, "root") { return nil } - subset, offending := helper.SliceStringIsSubset(allowedPolicies, jobPolicies) + subset, offending := helper.IsSubset(allowedPolicies, jobPolicies) if !subset { return fmt.Errorf("Vault token doesn't allow access to the following policies: %s", strings.Join(offending, ", ")) diff --git a/nomad/job_endpoint_hooks.go b/nomad/job_endpoint_hooks.go index 5ad972777..086680112 100644 --- a/nomad/job_endpoint_hooks.go +++ b/nomad/job_endpoint_hooks.go @@ -167,7 +167,7 @@ func (jobImpliedConstraints) Mutate(j *structs.Job) (*structs.Job, []error, erro // is, we flatten the signals and build a constraint, then run the // mutator. if tgSignals, ok := signals[tg.Name]; ok { - required := helper.MapStringStringSliceValueSet(tgSignals) + required := helper.UniqueMapSliceValues(tgSignals) sigConstraint := getSignalConstraint(required) mutateConstraint(constraintMatcherFull, tg, sigConstraint) } diff --git a/nomad/structs/config/audit.go b/nomad/structs/config/audit.go index 91a430164..c9459b584 100644 --- a/nomad/structs/config/audit.go +++ b/nomad/structs/config/audit.go @@ -3,8 +3,8 @@ package config import ( "time" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/helper/pointer" + "golang.org/x/exp/slices" ) // AuditConfig is the configuration specific to Audit Logging @@ -139,9 +139,9 @@ func (a *AuditFilter) Copy() *AuditFilter { *nc = *a // Copy slices - nc.Endpoints = helper.CopySliceString(nc.Endpoints) - nc.Stages = helper.CopySliceString(nc.Stages) - nc.Operations = helper.CopySliceString(nc.Operations) + nc.Endpoints = slices.Clone(nc.Endpoints) + nc.Stages = slices.Clone(nc.Stages) + nc.Operations = slices.Clone(nc.Operations) return nc } diff --git a/nomad/structs/csi.go b/nomad/structs/csi.go index 447ee523e..2f2d3423b 100644 --- a/nomad/structs/csi.go +++ b/nomad/structs/csi.go @@ -8,6 +8,8 @@ import ( multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/nomad/helper" + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" ) // CSISocketName is the filename that Nomad expects plugins to create inside the @@ -174,7 +176,7 @@ func (o *CSIMountOptions) Copy() *CSIMountOptions { } no := *o - no.MountFlags = helper.CopySliceString(o.MountFlags) + no.MountFlags = slices.Clone(o.MountFlags) return &no } @@ -197,13 +199,10 @@ func (o *CSIMountOptions) Equal(p *CSIMountOptions) bool { if o == nil || p == nil { return false } - if o.FSType != p.FSType { return false } - - return helper.CompareSliceSetString( - o.MountFlags, p.MountFlags) + return helper.SliceSetEq(o.MountFlags, p.MountFlags) } // CSIMountOptions implements the Stringer and GoStringer interfaces to prevent @@ -848,7 +847,7 @@ func (v *CSIVolume) Merge(other *CSIVolume) error { // must be compatible with parameters set by from CreateVolumeResponse - if len(other.Parameters) != 0 && !helper.CompareMapStringString(v.Parameters, other.Parameters) { + if len(other.Parameters) != 0 && !maps.Equal(v.Parameters, other.Parameters) { errs = multierror.Append(errs, errors.New( "volume parameters cannot be updated")) } diff --git a/nomad/structs/funcs.go b/nomad/structs/funcs.go index db6a2cef2..b3a114072 100644 --- a/nomad/structs/funcs.go +++ b/nomad/structs/funcs.go @@ -11,9 +11,9 @@ import ( "strings" multierror "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-set" lru "github.com/hashicorp/golang-lru" "github.com/hashicorp/nomad/acl" - "github.com/hashicorp/nomad/helper" "golang.org/x/crypto/blake2b" ) @@ -367,35 +367,29 @@ func CopySliceNodeScoreMeta(s []*NodeScoreMeta) []*NodeScoreMeta { // VaultPoliciesSet takes the structure returned by VaultPolicies and returns // the set of required policies func VaultPoliciesSet(policies map[string]map[string]*Vault) []string { - set := make(map[string]struct{}) - + s := set.New[string](10) for _, tgp := range policies { for _, tp := range tgp { if tp != nil { - for _, p := range tp.Policies { - set[p] = struct{}{} - } + s.InsertAll(tp.Policies) } } } - - return helper.SetToSliceString(set) + return s.List() } // VaultNamespaceSet takes the structure returned by VaultPolicies and // returns a set of required namespaces func VaultNamespaceSet(policies map[string]map[string]*Vault) []string { - set := make(map[string]struct{}) - + s := set.New[string](10) for _, tgp := range policies { for _, tp := range tgp { if tp != nil && tp.Namespace != "" { - set[tp.Namespace] = struct{}{} + s.Insert(tp.Namespace) } } } - - return helper.SetToSliceString(set) + return s.List() } // DenormalizeAllocationJobs is used to attach a job to all allocations that are diff --git a/nomad/structs/network.go b/nomad/structs/network.go index 5d2b035e3..81ae54cc7 100644 --- a/nomad/structs/network.go +++ b/nomad/structs/network.go @@ -6,7 +6,7 @@ import ( "net" "sync" - "github.com/hashicorp/nomad/helper" + "golang.org/x/exp/maps" ) const ( @@ -110,7 +110,7 @@ func (idx *NetworkIndex) Copy() *NetworkIndex { if idx.AvailBandwidth != nil && len(idx.AvailBandwidth) == 0 { c.AvailBandwidth = make(map[string]int) } else { - c.AvailBandwidth = helper.CopyMapStringInt(idx.AvailBandwidth) + c.AvailBandwidth = maps.Clone(idx.AvailBandwidth) } if len(idx.UsedPorts) > 0 { c.UsedPorts = make(map[string]Bitmap, len(idx.UsedPorts)) @@ -121,7 +121,7 @@ func (idx *NetworkIndex) Copy() *NetworkIndex { if idx.UsedBandwidth != nil && len(idx.UsedBandwidth) == 0 { c.UsedBandwidth = make(map[string]int) } else { - c.UsedBandwidth = helper.CopyMapStringInt(idx.UsedBandwidth) + c.UsedBandwidth = maps.Clone(idx.UsedBandwidth) } return c diff --git a/nomad/structs/node.go b/nomad/structs/node.go index 1dd7ed87c..1a50e29d5 100644 --- a/nomad/structs/node.go +++ b/nomad/structs/node.go @@ -4,7 +4,7 @@ import ( "reflect" "time" - "github.com/hashicorp/nomad/helper" + "golang.org/x/exp/maps" ) // CSITopology is a map of topological domains to topological segments. @@ -50,7 +50,7 @@ func (t *CSITopology) Copy() *CSITopology { } return &CSITopology{ - Segments: helper.CopyMapStringString(t.Segments), + Segments: maps.Clone(t.Segments), } } @@ -58,8 +58,7 @@ func (t *CSITopology) Equal(o *CSITopology) bool { if t == nil || o == nil { return t == o } - - return helper.CompareMapStringString(t.Segments, o.Segments) + return maps.Equal(t.Segments, o.Segments) } func (t *CSITopology) MatchFound(o []*CSITopology) bool { @@ -315,7 +314,7 @@ func (di *DriverInfo) Copy() *DriverInfo { cdi := new(DriverInfo) *cdi = *di - cdi.Attributes = helper.CopyMapStringString(di.Attributes) + cdi.Attributes = maps.Clone(di.Attributes) return cdi } diff --git a/nomad/structs/service_registration.go b/nomad/structs/service_registration.go index 9929e83fc..1e42cd736 100644 --- a/nomad/structs/service_registration.go +++ b/nomad/structs/service_registration.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/helper/ipaddr" + "golang.org/x/exp/slices" ) const ( @@ -100,7 +101,7 @@ func (s *ServiceRegistration) Copy() *ServiceRegistration { ns := new(ServiceRegistration) *ns = *s - ns.Tags = helper.CopySliceString(ns.Tags) + ns.Tags = slices.Clone(ns.Tags) return ns } @@ -138,7 +139,7 @@ func (s *ServiceRegistration) Equals(o *ServiceRegistration) bool { if s.Port != o.Port { return false } - if !helper.CompareSliceSetString(s.Tags, o.Tags) { + if !helper.SliceSetEq(s.Tags, o.Tags) { return false } return true diff --git a/nomad/structs/services.go b/nomad/structs/services.go index a8d1a28b8..b4ff34c0c 100644 --- a/nomad/structs/services.go +++ b/nomad/structs/services.go @@ -22,6 +22,7 @@ import ( "github.com/hashicorp/nomad/helper/args" "github.com/hashicorp/nomad/helper/pointer" "github.com/mitchellh/copystructure" + "golang.org/x/exp/maps" "golang.org/x/exp/slices" ) @@ -90,8 +91,8 @@ func (sc *ServiceCheck) Copy() *ServiceCheck { } nsc := new(ServiceCheck) *nsc = *sc - nsc.Args = helper.CopySliceString(sc.Args) - nsc.Header = helper.CopyMapStringSliceString(sc.Header) + nsc.Args = slices.Clone(sc.Args) + nsc.Header = helper.CopyMapOfSlice(sc.Header) nsc.CheckRestart = sc.CheckRestart.Copy() return nsc } @@ -110,7 +111,7 @@ func (sc *ServiceCheck) Equals(o *ServiceCheck) bool { return false } - if !helper.CompareSliceSetString(sc.Args, o.Args) { + if !helper.SliceSetEq(sc.Args, o.Args) { return false } @@ -409,13 +410,13 @@ func (sc *ServiceCheck) validateConsul() error { if sc.SuccessBeforePassing < 0 { return fmt.Errorf("success_before_passing must be non-negative") - } else if sc.SuccessBeforePassing > 0 && !helper.SliceStringContains(passFailCheckTypes, sc.Type) { + } else if sc.SuccessBeforePassing > 0 && !slices.Contains(passFailCheckTypes, sc.Type) { return fmt.Errorf("success_before_passing not supported for check of type %q", sc.Type) } if sc.FailuresBeforeCritical < 0 { return fmt.Errorf("failures_before_critical must be non-negative") - } else if sc.FailuresBeforeCritical > 0 && !helper.SliceStringContains(passFailCheckTypes, sc.Type) { + } else if sc.FailuresBeforeCritical > 0 && !slices.Contains(passFailCheckTypes, sc.Type) { return fmt.Errorf("failures_before_critical not supported for check of type %q", sc.Type) } @@ -601,8 +602,8 @@ func (s *Service) Copy() *Service { } ns := new(Service) *ns = *s - ns.Tags = helper.CopySliceString(ns.Tags) - ns.CanaryTags = helper.CopySliceString(ns.CanaryTags) + ns.Tags = slices.Clone(ns.Tags) + ns.CanaryTags = slices.Clone(ns.CanaryTags) if s.Checks != nil { checks := make([]*ServiceCheck, len(ns.Checks)) @@ -614,9 +615,9 @@ func (s *Service) Copy() *Service { ns.Connect = s.Connect.Copy() - ns.Meta = helper.CopyMapStringString(s.Meta) - ns.CanaryMeta = helper.CopyMapStringString(s.CanaryMeta) - ns.TaggedAddresses = helper.CopyMapStringString(s.TaggedAddresses) + ns.Meta = maps.Clone(s.Meta) + ns.CanaryMeta = maps.Clone(s.CanaryMeta) + ns.TaggedAddresses = maps.Clone(s.TaggedAddresses) return ns } @@ -908,7 +909,7 @@ func (s *Service) Equals(o *Service) bool { return false } - if !helper.CompareSliceSetString(s.CanaryTags, o.CanaryTags) { + if !helper.SliceSetEq(s.CanaryTags, o.CanaryTags) { return false } @@ -928,19 +929,19 @@ func (s *Service) Equals(o *Service) bool { return false } - if !helper.CompareMapStringString(s.Meta, o.Meta) { + if !maps.Equal(s.Meta, o.Meta) { return false } - if !helper.CompareMapStringString(s.CanaryMeta, o.CanaryMeta) { + if !maps.Equal(s.CanaryMeta, o.CanaryMeta) { return false } - if !helper.CompareMapStringString(s.TaggedAddresses, o.TaggedAddresses) { + if !maps.Equal(s.TaggedAddresses, o.TaggedAddresses) { return false } - if !helper.CompareSliceSetString(s.Tags, o.Tags) { + if !helper.SliceSetEq(s.Tags, o.Tags) { return false } @@ -1112,7 +1113,7 @@ func (s *ConsulSidecarService) Copy() *ConsulSidecarService { return nil } return &ConsulSidecarService{ - Tags: helper.CopySliceString(s.Tags), + Tags: slices.Clone(s.Tags), Port: s.Port, Proxy: s.Proxy.Copy(), DisableDefaultTCPCheck: s.DisableDefaultTCPCheck, @@ -1133,7 +1134,7 @@ func (s *ConsulSidecarService) Equals(o *ConsulSidecarService) bool { return false } - if !helper.CompareSliceSetString(s.Tags, o.Tags) { + if !helper.SliceSetEq(s.Tags, o.Tags) { return false } @@ -1204,7 +1205,7 @@ func (t *SidecarTask) Equals(o *SidecarTask) bool { return false } - if !helper.CompareMapStringString(t.Env, o.Env) { + if !maps.Equal(t.Env, o.Env) { return false } @@ -1212,7 +1213,7 @@ func (t *SidecarTask) Equals(o *SidecarTask) bool { return false } - if !helper.CompareMapStringString(t.Meta, o.Meta) { + if !maps.Equal(t.Meta, o.Meta) { return false } @@ -1241,11 +1242,11 @@ func (t *SidecarTask) Copy() *SidecarTask { } nt := new(SidecarTask) *nt = *t - nt.Env = helper.CopyMapStringString(nt.Env) + nt.Env = maps.Clone(nt.Env) nt.Resources = nt.Resources.Copy() nt.LogConfig = nt.LogConfig.Copy() - nt.Meta = helper.CopyMapStringString(nt.Meta) + nt.Meta = maps.Clone(nt.Meta) if i, err := copystructure.Copy(nt.Config); err != nil { panic(err.Error()) @@ -1374,7 +1375,7 @@ func (p *ConsulProxy) Copy() *ConsulProxy { LocalServicePort: p.LocalServicePort, Expose: p.Expose.Copy(), Upstreams: slices.Clone(p.Upstreams), - Config: helper.CopyMap(p.Config), + Config: maps.Clone(p.Config), } } @@ -1707,7 +1708,7 @@ func (p *ConsulGatewayProxy) Copy() *ConsulGatewayProxy { EnvoyGatewayBindAddresses: p.copyBindAddresses(), EnvoyGatewayNoDefaultBind: p.EnvoyGatewayNoDefaultBind, EnvoyDNSDiscoveryType: p.EnvoyDNSDiscoveryType, - Config: helper.CopyMapStringInterface(p.Config), + Config: maps.Clone(p.Config), } } @@ -1818,7 +1819,7 @@ func (c *ConsulGatewayTLSConfig) Copy() *ConsulGatewayTLSConfig { Enabled: c.Enabled, TLSMinVersion: c.TLSMinVersion, TLSMaxVersion: c.TLSMaxVersion, - CipherSuites: helper.CopySliceString(c.CipherSuites), + CipherSuites: slices.Clone(c.CipherSuites), } } @@ -1830,7 +1831,7 @@ func (c *ConsulGatewayTLSConfig) Equals(o *ConsulGatewayTLSConfig) bool { return c.Enabled == o.Enabled && c.TLSMinVersion == o.TLSMinVersion && c.TLSMaxVersion == o.TLSMaxVersion && - helper.CompareSliceSetString(c.CipherSuites, o.CipherSuites) + helper.SliceSetEq(c.CipherSuites, o.CipherSuites) } // ConsulIngressService is used to configure a service fronted by the ingress gateway. @@ -1865,7 +1866,7 @@ func (s *ConsulIngressService) Equals(o *ConsulIngressService) bool { return false } - return helper.CompareSliceSetString(s.Hosts, o.Hosts) + return helper.SliceSetEq(s.Hosts, o.Hosts) } func (s *ConsulIngressService) Validate(protocol string) error { @@ -1956,7 +1957,7 @@ func (l *ConsulIngressListener) Validate() error { } protocols := []string{"tcp", "http", "http2", "grpc"} - if !helper.SliceStringContains(protocols, l.Protocol) { + if !slices.Contains(protocols, l.Protocol) { return fmt.Errorf(`Consul Ingress Listener requires protocol of %s, got %q`, strings.Join(protocols, ", "), l.Protocol) } diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index 819b378e7..54d7d9348 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -45,6 +45,7 @@ import ( "github.com/miekg/dns" "github.com/mitchellh/copystructure" "golang.org/x/crypto/blake2b" + "golang.org/x/exp/maps" "golang.org/x/exp/slices" ) @@ -1691,7 +1692,7 @@ func (ne *NodeEvent) String() string { func (ne *NodeEvent) Copy() *NodeEvent { c := new(NodeEvent) *c = *ne - c.Details = helper.CopyMapStringString(ne.Details) + c.Details = maps.Clone(ne.Details) return c } @@ -1878,7 +1879,7 @@ func (m *DrainMetadata) Copy() *DrainMetadata { } c := new(DrainMetadata) *c = *m - c.Meta = helper.CopyMapStringString(m.Meta) + c.Meta = maps.Clone(m.Meta) return c } @@ -2068,13 +2069,13 @@ func (n *Node) Copy() *Node { return nil } nn := *n - nn.Attributes = helper.CopyMap(nn.Attributes) + nn.Attributes = maps.Clone(nn.Attributes) nn.NodeResources = nn.NodeResources.Copy() nn.ReservedResources = nn.ReservedResources.Copy() nn.Resources = nn.Resources.Copy() nn.Reserved = nn.Reserved.Copy() - nn.Links = helper.CopyMapStringString(nn.Links) - nn.Meta = helper.CopyMapStringString(nn.Meta) + nn.Links = maps.Clone(nn.Links) + nn.Meta = maps.Clone(nn.Meta) nn.DrainStrategy = nn.DrainStrategy.Copy() nn.Events = helper.CopySlice(n.Events) nn.Drivers = helper.DeepCopyMap(n.Drivers) @@ -4252,7 +4253,7 @@ func (j *Job) Copy() *Job { } nj := new(Job) *nj = *j - nj.Datacenters = helper.CopySliceString(nj.Datacenters) + nj.Datacenters = slices.Clone(nj.Datacenters) nj.Constraints = CopySliceConstraints(nj.Constraints) nj.Affinities = CopySliceAffinities(nj.Affinities) nj.Multiregion = nj.Multiregion.Copy() @@ -4266,7 +4267,7 @@ func (j *Job) Copy() *Job { } nj.Periodic = nj.Periodic.Copy() - nj.Meta = helper.CopyMapStringString(nj.Meta) + nj.Meta = maps.Clone(nj.Meta) nj.ParameterizedJob = nj.ParameterizedJob.Copy() return nj } @@ -4474,7 +4475,7 @@ func (j *Job) CombinedTaskMeta(groupName, taskName string) map[string]string { task := group.LookupTask(taskName) if task != nil { - meta = helper.CopyMapStringString(task.Meta) + meta = maps.Clone(task.Meta) } if meta == nil { @@ -5080,8 +5081,8 @@ func (n *Namespace) Copy() *Namespace { if n.Capabilities != nil { c := new(NamespaceCapabilities) *c = *n.Capabilities - c.EnabledTaskDrivers = helper.CopySliceString(n.Capabilities.EnabledTaskDrivers) - c.DisabledTaskDrivers = helper.CopySliceString(n.Capabilities.DisabledTaskDrivers) + c.EnabledTaskDrivers = slices.Clone(n.Capabilities.EnabledTaskDrivers) + c.DisabledTaskDrivers = slices.Clone(n.Capabilities.DisabledTaskDrivers) nc.Capabilities = c } if n.Meta != nil { @@ -5339,7 +5340,7 @@ func (d *ParameterizedJobConfig) Validate() error { } // Check that the meta configurations are disjoint sets - disjoint, offending := helper.SliceSetDisjoint(d.MetaRequired, d.MetaOptional) + disjoint, offending := helper.IsDisjoint(d.MetaRequired, d.MetaOptional) if !disjoint { _ = multierror.Append(&mErr, fmt.Errorf("Required and optional meta keys should be disjoint. Following keys exist in both: %v", offending)) } @@ -5359,8 +5360,8 @@ func (d *ParameterizedJobConfig) Copy() *ParameterizedJobConfig { } nd := new(ParameterizedJobConfig) *nd = *d - nd.MetaOptional = helper.CopySliceString(nd.MetaOptional) - nd.MetaRequired = helper.CopySliceString(nd.MetaRequired) + nd.MetaOptional = slices.Clone(nd.MetaOptional) + nd.MetaRequired = slices.Clone(nd.MetaRequired) return nd } @@ -6195,7 +6196,7 @@ func (tg *TaskGroup) Copy() *TaskGroup { ntg.Tasks = tasks } - ntg.Meta = helper.CopyMapStringString(ntg.Meta) + ntg.Meta = maps.Clone(ntg.Meta) if tg.EphemeralDisk != nil { ntg.EphemeralDisk = tg.EphemeralDisk.Copy() @@ -7073,7 +7074,7 @@ func (t *Task) Copy() *Task { } nt := new(Task) *nt = *t - nt.Env = helper.CopyMapStringString(nt.Env) + nt.Env = maps.Clone(nt.Env) if t.Services != nil { services := make([]*Service, len(nt.Services)) @@ -7091,7 +7092,7 @@ func (t *Task) Copy() *Task { nt.Vault = nt.Vault.Copy() nt.Resources = nt.Resources.Copy() nt.LogConfig = nt.LogConfig.Copy() - nt.Meta = helper.CopyMapStringString(nt.Meta) + nt.Meta = maps.Clone(nt.Meta) nt.DispatchPayload = nt.DispatchPayload.Copy() nt.Lifecycle = nt.Lifecycle.Copy() @@ -8567,8 +8568,8 @@ func (ta *TaskArtifact) Copy() *TaskArtifact { } return &TaskArtifact{ GetterSource: ta.GetterSource, - GetterOptions: helper.CopyMapStringString(ta.GetterOptions), - GetterHeaders: helper.CopyMapStringString(ta.GetterHeaders), + GetterOptions: maps.Clone(ta.GetterOptions), + GetterHeaders: maps.Clone(ta.GetterHeaders), GetterMode: ta.GetterMode, RelativeDest: ta.RelativeDest, } @@ -9441,7 +9442,7 @@ func (d *DeploymentState) GoString() string { func (d *DeploymentState) Copy() *DeploymentState { c := &DeploymentState{} *c = *d - c.PlacedCanaries = helper.CopySliceString(d.PlacedCanaries) + c.PlacedCanaries = slices.Clone(d.PlacedCanaries) return c } @@ -9855,7 +9856,7 @@ func (a *Allocation) copyImpl(job bool) *Allocation { } na.RescheduleTracker = a.RescheduleTracker.Copy() - na.PreemptedAllocations = helper.CopySliceString(a.PreemptedAllocations) + na.PreemptedAllocations = slices.Clone(a.PreemptedAllocations) return na } @@ -10584,13 +10585,13 @@ func (a *AllocMetric) Copy() *AllocMetric { } na := new(AllocMetric) *na = *a - na.NodesAvailable = helper.CopyMapStringInt(na.NodesAvailable) - na.ClassFiltered = helper.CopyMapStringInt(na.ClassFiltered) - na.ConstraintFiltered = helper.CopyMapStringInt(na.ConstraintFiltered) - na.ClassExhausted = helper.CopyMapStringInt(na.ClassExhausted) - na.DimensionExhausted = helper.CopyMapStringInt(na.DimensionExhausted) - na.QuotaExhausted = helper.CopySliceString(na.QuotaExhausted) - na.Scores = helper.CopyMapStringFloat64(na.Scores) + na.NodesAvailable = maps.Clone(na.NodesAvailable) + na.ClassFiltered = maps.Clone(na.ClassFiltered) + na.ConstraintFiltered = maps.Clone(na.ConstraintFiltered) + na.ClassExhausted = maps.Clone(na.ClassExhausted) + na.DimensionExhausted = maps.Clone(na.DimensionExhausted) + na.QuotaExhausted = slices.Clone(na.QuotaExhausted) + na.Scores = maps.Clone(na.Scores) na.ScoreMetaData = CopySliceNodeScoreMeta(na.ScoreMetaData) return na } diff --git a/plugins/csi/client.go b/plugins/csi/client.go index 934a12690..486f72ce3 100644 --- a/plugins/csi/client.go +++ b/plugins/csi/client.go @@ -11,11 +11,11 @@ import ( csipbv1 "github.com/container-storage-interface/spec/lib/go/csi" "github.com/hashicorp/go-hclog" multierror "github.com/hashicorp/go-multierror" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/helper/grpc-middleware/logging" "github.com/hashicorp/nomad/nomad/structs" "github.com/hashicorp/nomad/plugins/base" "github.com/hashicorp/nomad/plugins/shared/hclspec" + "golang.org/x/exp/maps" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -327,7 +327,7 @@ func (c *client) ControllerPublishVolume(ctx context.Context, req *ControllerPub } return &ControllerPublishVolumeResponse{ - PublishContext: helper.CopyMapStringString(resp.PublishContext), + PublishContext: maps.Clone(resp.PublishContext), }, nil } diff --git a/plugins/drivers/driver.go b/plugins/drivers/driver.go index 4b8cd7d13..505591ea1 100644 --- a/plugins/drivers/driver.go +++ b/plugins/drivers/driver.go @@ -12,7 +12,6 @@ import ( "github.com/hashicorp/nomad/client/allocdir" cstructs "github.com/hashicorp/nomad/client/structs" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/nomad/structs" "github.com/hashicorp/nomad/plugins/base" "github.com/hashicorp/nomad/plugins/drivers/proto" @@ -20,6 +19,7 @@ import ( pstructs "github.com/hashicorp/nomad/plugins/shared/structs" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/msgpack" + "golang.org/x/exp/maps" ) const ( @@ -292,8 +292,8 @@ func (tc *TaskConfig) Copy() *TaskConfig { } c := new(TaskConfig) *c = *tc - c.Env = helper.CopyMapStringString(c.Env) - c.DeviceEnv = helper.CopyMapStringString(c.DeviceEnv) + c.Env = maps.Clone(c.Env) + c.DeviceEnv = maps.Clone(c.DeviceEnv) c.Resources = tc.Resources.Copy() c.DNS = tc.DNS.Copy() diff --git a/scheduler/generic_sched_test.go b/scheduler/generic_sched_test.go index 1c23c806d..4b99f9e75 100644 --- a/scheduler/generic_sched_test.go +++ b/scheduler/generic_sched_test.go @@ -9,7 +9,6 @@ import ( memdb "github.com/hashicorp/go-memdb" "github.com/hashicorp/nomad/ci" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/helper/pointer" "github.com/hashicorp/nomad/helper/uuid" "github.com/hashicorp/nomad/nomad/mock" @@ -17,6 +16,7 @@ import ( "github.com/hashicorp/nomad/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "golang.org/x/exp/slices" ) func TestServiceSched_JobRegister(t *testing.T) { @@ -1731,7 +1731,7 @@ func TestServiceSched_JobModify_Datacenters(t *testing.T) { placed := map[string]*structs.Allocation{} for node, placedAllocs := range plan.NodeAllocation { require.True( - helper.SliceStringContains([]string{nodes[0].ID, nodes[1].ID}, node), + slices.Contains([]string{nodes[0].ID, nodes[1].ID}, node), "allocation placed on ineligible node", ) for _, alloc := range placedAllocs { diff --git a/scheduler/util.go b/scheduler/util.go index 796f84b5a..ac802f099 100644 --- a/scheduler/util.go +++ b/scheduler/util.go @@ -9,8 +9,8 @@ import ( log "github.com/hashicorp/go-hclog" memdb "github.com/hashicorp/go-memdb" - "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/nomad/structs" + "golang.org/x/exp/slices" ) // allocTuple is a tuple of the allocation name and potential alloc ID @@ -860,7 +860,7 @@ func inplaceUpdate(ctx Context, eval *structs.Evaluation, job *structs.Job, } // The alloc is on a node that's now in an ineligible DC - if !helper.SliceStringContains(job.Datacenters, node.Datacenter) { + if !slices.Contains(job.Datacenters, node.Datacenter) { continue } @@ -1148,7 +1148,7 @@ func genericAllocUpdateFn(ctx Context, stack Stack, evalID string) allocUpdateTy } // The alloc is on a node that's now in an ineligible DC - if !helper.SliceStringContains(newJob.Datacenters, node.Datacenter) { + if !slices.Contains(newJob.Datacenters, node.Datacenter) { return false, true, nil }