diff --git a/subcommand/server-acl-init/command_test.go b/subcommand/server-acl-init/command_test.go index 5a70aafb5f..c943251590 100644 --- a/subcommand/server-acl-init/command_test.go +++ b/subcommand/server-acl-init/command_test.go @@ -394,7 +394,7 @@ func TestRun_TokensReplicatedDC(t *testing.T) { tokenFile, fileCleanup := writeTempFile(t, bootToken) defer fileCleanup() - k8s, consul, cleanup := completeReplicatedSetup(t, resourcePrefix, bootToken) + k8s, consul, cleanup := mockReplicatedSetup(t, resourcePrefix, bootToken) defer cleanup() // Run the command. @@ -1488,73 +1488,11 @@ func TestRun_HTTPS(t *testing.T) { func TestRun_ACLReplicationTokenValid(t *testing.T) { t.Parallel() - // Set up the primary DC first. - primarySvr, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { - c.ACL.Enabled = true - }) - require.NoError(t, err) - defer primarySvr.Stop() - - primaryK8s := fake.NewSimpleClientset() - createTestK8SResources(t, primaryK8s, primarySvr.HTTPAddr, resourcePrefix, "http", ns) - require.NoError(t, err) - - // Run the command to bootstrap ACLs - primaryUI := cli.NewMockUi() - primaryCmd := Command{ - UI: primaryUI, - clientset: primaryK8s, - } - primaryCmd.init() - primaryCmdArgs := []string{ - "-k8s-namespace=" + ns, - "-expected-replicas=1", - "-server-label-selector=component=server,app=consul,release=" + releaseName, - "-resource-prefix=" + resourcePrefix, - "-create-acl-replication-token", - } - responseCode := primaryCmd.Run(primaryCmdArgs) - require.Equal(t, 0, responseCode, primaryUI.ErrorWriter.String()) - - // Retrieve the replication ACL token from the kubernetes secret. - tokenSecret, err := primaryK8s.CoreV1().Secrets(ns).Get("release-name-consul-acl-replication-acl-token", metav1.GetOptions{}) - require.NoError(t, err) - require.NotNil(t, tokenSecret) - aclReplicationTokenBytes, ok := tokenSecret.Data["token"] - require.True(t, ok) - aclReplicationToken := string(aclReplicationTokenBytes) - - // Now we can set up the secondary DC. - secondarySvr, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { - c.Datacenter = "dc2" - c.ACL.Enabled = true - c.ACL.TokenReplication = true - c.PrimaryDatacenter = "dc1" - // When running via the Helm chart these are passed in to the servers. - c.ACL.Tokens.Agent = aclReplicationToken - c.ACL.Tokens.Replication = aclReplicationToken - }) - require.NoError(t, err) - defer secondarySvr.Stop() - - bootToken := getBootToken(t, primaryK8s, resourcePrefix, ns) - secondaryConsulClient, err := api.NewClient(&api.Config{ - Address: secondarySvr.HTTPAddr, - // When running via Helm, the WAN join config is set in the server config - // however that config isn't exposed by the testutil server so instead we need to - // make the join API call. This requires the bootstrap token permissions. - // The token here isn't that important because we're only using this - // client to make our own test assertions. The underlying code we're - // testing uses the replication token. - Token: bootToken, - }) - err = secondaryConsulClient.Agent().Join(primarySvr.WANAddr, true) - require.NoError(t, err) - - secondaryK8s := fake.NewSimpleClientset() - createTestK8SResources(t, secondaryK8s, secondarySvr.HTTPAddr, resourcePrefix, "http", ns) + secondaryK8s, secondaryConsulClient, aclReplicationToken, clean := completeReplicatedSetup(t, resourcePrefix) + defer clean() - // Now we're ready to run the command in our secondary dc. + // completeReplicatedSetup ran the command in our primary dc so now we + // need to run the command in our secondary dc. tokenFile, cleanup := writeTempFile(t, aclReplicationToken) defer cleanup() secondaryUI := cli.NewMockUi() @@ -1572,7 +1510,7 @@ func TestRun_ACLReplicationTokenValid(t *testing.T) { "-create-client-token", "-create-mesh-gateway-token", } - responseCode = secondaryCmd.Run(secondaryCmdArgs) + responseCode := secondaryCmd.Run(secondaryCmdArgs) require.Equal(t, 0, responseCode, secondaryUI.ErrorWriter.String()) // Test that replication was successful. @@ -1602,7 +1540,7 @@ func TestRun_AllowDNSFlag_IgnoredWithReplication(t *testing.T) { bootToken := "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" tokenFile, fileCleanup := writeTempFile(t, bootToken) defer fileCleanup() - k8s, consul, cleanup := completeReplicatedSetup(t, resourcePrefix, bootToken) + k8s, consul, cleanup := mockReplicatedSetup(t, resourcePrefix, bootToken) defer cleanup() // Run the command. @@ -1647,35 +1585,97 @@ func completeSetup(t *testing.T, prefix string) (*fake.Clientset, *testutil.Test return k8s, svr } -// Set up two Consul servers with ACL replication. +// completeReplicatedSetup sets up two Consul servers with ACL replication +// using the server-acl-init command to start the replication. +// Returns the Kubernetes client for the secondary DC, +// a Consul API client initialized for the secondary DC, the replication token +// generated and a cleanup function that should be called at the end of the +// test that cleans up resources. +func completeReplicatedSetup(t *testing.T, prefix string) (*fake.Clientset, *api.Client, string, func()) { + return replicatedSetup(t, prefix, "") +} + +// mockReplicatedSetup sets up two Consul servers with ACL replication. +// It's a mock setup because we don't run the server-acl-init +// command to set up replication but do it in config using the bootstrap +// token. See completeReplicatedSetup for a complete setup using the command. // Returns the Kubernetes client for the secondary DC, // a Consul API client initialized for the secondary DC and a // cleanup function that should be called at the end of the test that cleans // up resources. -func completeReplicatedSetup(t *testing.T, prefix string, bootToken string) (*fake.Clientset, *api.Client, func()) { - t.Helper() +func mockReplicatedSetup(t *testing.T, prefix string, bootToken string) (*fake.Clientset, *api.Client, func()) { + k8sClient, consulClient, _, cleanup := replicatedSetup(t, prefix, bootToken) + return k8sClient, consulClient, cleanup +} +// replicatedSetup is a helper function for completeReplicatedSetup and +// mockReplicatedSetup. If bootToken is empty, it will run the server-acl-init +// command to set up replication. Otherwise it will do it through config. +func replicatedSetup(t *testing.T, prefix string, bootToken string) (*fake.Clientset, *api.Client, string, func()) { primarySvr, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { c.ACL.Enabled = true - c.ACL.Tokens.Master = bootToken + if bootToken != "" { + c.ACL.Tokens.Master = bootToken + } }) require.NoError(t, err) + var aclReplicationToken string + if bootToken == "" { + primaryK8s := fake.NewSimpleClientset() + createTestK8SResources(t, primaryK8s, primarySvr.HTTPAddr, resourcePrefix, "http", ns) + require.NoError(t, err) + + // Run the command to bootstrap ACLs + primaryUI := cli.NewMockUi() + primaryCmd := Command{ + UI: primaryUI, + clientset: primaryK8s, + } + primaryCmd.init() + primaryCmdArgs := []string{ + "-k8s-namespace=" + ns, + "-expected-replicas=1", + "-server-label-selector=component=server,app=consul,release=" + releaseName, + "-resource-prefix=" + resourcePrefix, + "-create-acl-replication-token", + } + responseCode := primaryCmd.Run(primaryCmdArgs) + require.Equal(t, 0, responseCode, primaryUI.ErrorWriter.String()) + + // Retrieve the replication ACL token from the kubernetes secret. + tokenSecret, err := primaryK8s.CoreV1().Secrets(ns).Get("release-name-consul-acl-replication-acl-token", metav1.GetOptions{}) + require.NoError(t, err) + require.NotNil(t, tokenSecret) + aclReplicationTokenBytes, ok := tokenSecret.Data["token"] + require.True(t, ok) + aclReplicationToken = string(aclReplicationTokenBytes) + } + // Set up the secondary server that will federate with the primary. secondarySvr, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { c.Datacenter = "dc2" c.ACL.Enabled = true c.ACL.TokenReplication = true - c.ACL.Tokens.Agent = bootToken - c.ACL.Tokens.Replication = bootToken c.PrimaryDatacenter = "dc1" + if bootToken == "" { + c.ACL.Tokens.Agent = aclReplicationToken + c.ACL.Tokens.Replication = aclReplicationToken + } else { + c.ACL.Tokens.Agent = bootToken + c.ACL.Tokens.Replication = bootToken + } }) require.NoError(t, err) // Our consul client will use the secondary dc. + clientToken := bootToken + if bootToken == "" { + clientToken = aclReplicationToken + } consul, err := api.NewClient(&api.Config{ Address: secondarySvr.HTTPAddr, - Token: bootToken, + Token: clientToken, }) require.NoError(t, err) @@ -1687,7 +1687,7 @@ func completeReplicatedSetup(t *testing.T, prefix string, bootToken string) (*fa k8s := fake.NewSimpleClientset() createTestK8SResources(t, k8s, secondarySvr.HTTPAddr, prefix, "http", ns) - return k8s, consul, func() { + return k8s, consul, aclReplicationToken, func() { primarySvr.Stop() secondarySvr.Stop() }