Skip to content

Commit 6f3b124

Browse files
implement methods to handle namespace create and delete
1 parent da0e454 commit 6f3b124

File tree

4 files changed

+132
-11
lines changed

4 files changed

+132
-11
lines changed

clusterctl/clusterdeployer/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ go_library(
1919
"//pkg/util:go_default_library",
2020
"//vendor/github.com/golang/glog:go_default_library",
2121
"//vendor/k8s.io/api/core/v1:go_default_library",
22+
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
2223
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
2324
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
2425
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",

clusterctl/clusterdeployer/clusterclient.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"time"
2626

2727
apiv1 "k8s.io/api/core/v1"
28+
apierrors "k8s.io/apimachinery/pkg/api/errors"
2829
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2930
tcmd "k8s.io/client-go/tools/clientcmd"
3031
clusterv1 "sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1"
@@ -73,6 +74,37 @@ func (c *clusterClient) removeKubeconfigFile() error {
7374
return os.Remove(c.kubeconfigFile)
7475
}
7576

77+
func (c *clusterClient) EnsureNamespace(namespaceName string) error {
78+
clientset, err := clientcmd.NewCoreClientSetForKubeconfig(c.kubeconfigFile)
79+
if err != nil {
80+
return fmt.Errorf("error creating core clientset: %v", err)
81+
}
82+
83+
namespace := apiv1.Namespace{
84+
ObjectMeta: metav1.ObjectMeta{
85+
Name: namespaceName,
86+
},
87+
}
88+
_, err = clientset.CoreV1().Namespaces().Create(&namespace)
89+
if err != nil && !apierrors.IsAlreadyExists(err) {
90+
return err
91+
}
92+
return nil
93+
}
94+
95+
func (c *clusterClient) DeleteNamespace(namespaceName string) error {
96+
clientset, err := clientcmd.NewCoreClientSetForKubeconfig(c.kubeconfigFile)
97+
if err != nil {
98+
return fmt.Errorf("error creating core clientset: %v", err)
99+
}
100+
101+
err = clientset.CoreV1().Namespaces().Delete(namespaceName, &metav1.DeleteOptions{})
102+
if err != nil && !apierrors.IsNotFound(err) {
103+
return err
104+
}
105+
return nil
106+
}
107+
76108
// NewClusterClientFromDefaultSearchPath creates and returns the address of a clusterClient, the kubeconfigFile argument is expected to be the path to a
77109
// valid kubeconfig file.
78110
func NewClusterClientFromDefaultSearchPath(kubeconfigFile string, overrides tcmd.ConfigOverrides) (*clusterClient, error) {
@@ -197,7 +229,7 @@ func (c *clusterClient) GetMachineObjects() ([]*clusterv1.Machine, error) {
197229
}
198230

199231
func (c *clusterClient) CreateClusterObject(cluster *clusterv1.Cluster) error {
200-
namespace := c.configOverrides.Context.Namespace
232+
namespace := c.GetContextNamespace()
201233
if cluster.Namespace != "" {
202234
namespace = cluster.Namespace
203235
}

clusterctl/clusterdeployer/clusterdeployer.go

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ type ClusterClient interface {
7676
DeleteMachineObjectsInNamespace(string) error
7777
DeleteMachineObjects() error
7878
UpdateClusterObjectEndpoint(string, string, string) error
79+
EnsureNamespace(string) error
80+
DeleteNamespace(string) error
7981
Close() error
8082
}
8183

@@ -140,7 +142,11 @@ func (d *ClusterDeployer) Create(cluster *clusterv1.Cluster, machines []*cluster
140142
if cluster.Namespace == "" {
141143
cluster.Namespace = bootstrapClient.GetContextNamespace()
142144
}
143-
// TODO: @ashisha Create cluster.Namespace in bootstrap and target clusters?
145+
146+
err = bootstrapClient.EnsureNamespace(cluster.Namespace)
147+
if err != nil {
148+
return fmt.Errorf("unable to ensure namespace %q in bootstrap cluster: %v", cluster.Namespace, err)
149+
}
144150

145151
glog.Info("Applying Cluster API stack to bootstrap cluster")
146152
if err := d.applyClusterAPIStack(bootstrapClient, cluster.Namespace); err != nil {
@@ -165,7 +171,7 @@ func (d *ClusterDeployer) Create(cluster *clusterv1.Cluster, machines []*cluster
165171
}
166172

167173
glog.Info("Creating target cluster")
168-
targetClient, err := d.createTargetCluster(bootstrapClient, provider, kubeconfigOutput, cluster.Name, cluster.Namespace)
174+
targetClient, err := d.createTargetClusterClient(bootstrapClient, provider, kubeconfigOutput, cluster.Name, cluster.Namespace)
169175
if err != nil {
170176
return fmt.Errorf("unable to create target cluster: %v", err)
171177
}
@@ -182,6 +188,11 @@ func (d *ClusterDeployer) Create(cluster *clusterv1.Cluster, machines []*cluster
182188
return fmt.Errorf("unable to save provider components to target cluster: %v", err)
183189
}
184190

191+
err = targetClient.EnsureNamespace(cluster.Namespace)
192+
if err != nil {
193+
return fmt.Errorf("unable to ensure namespace %q in targetCluster: %v", cluster.Namespace, err)
194+
}
195+
185196
// For some reason, endpoint doesn't get updated in bootstrap cluster sometimes. So we
186197
// update the target cluster endpoint as well to be sure.
187198
glog.Infof("Updating target cluster object with master (%s) endpoint", master.Name)
@@ -235,6 +246,7 @@ func (d *ClusterDeployer) Delete(targetClient ClusterClient, namespace string) e
235246
if err = deleteObjectsInNamespace(bootstrapClient, namespace); err != nil {
236247
return fmt.Errorf("unable to finish deleting objects in bootstrap cluster, resources may have been leaked: %v", err)
237248
}
249+
238250
glog.Info("Deletion of cluster complete")
239251

240252
return nil
@@ -265,7 +277,7 @@ func (d *ClusterDeployer) createBootstrapCluster() (ClusterClient, func(), error
265277
return bootstrapClient, cleanupFn, nil
266278
}
267279

268-
func (d *ClusterDeployer) createTargetCluster(bootstrapClient ClusterClient, provider ProviderDeployer, kubeconfigOutput, clusterName, namespace string) (ClusterClient, error) {
280+
func (d *ClusterDeployer) createTargetClusterClient(bootstrapClient ClusterClient, provider ProviderDeployer, kubeconfigOutput, clusterName, namespace string) (ClusterClient, error) {
269281
cluster, master, _, err := getClusterAPIObject(bootstrapClient, clusterName, namespace)
270282
if err != nil {
271283
return nil, err
@@ -470,26 +482,31 @@ func pivotNamespace(from, to ClusterClient, namespace string) error {
470482

471483
func deleteObjectsInNamespace(client ClusterClient, namespace string) error {
472484
var errors []string
473-
glog.Infof("Deleting machine deployments")
485+
glog.Infof("Deleting machine deployments in namespace %q", namespace)
474486
if err := client.DeleteMachineDeploymentObjectsInNamespace(namespace); err != nil {
475487
err = fmt.Errorf("error deleting machine deployments: %v", err)
476488
errors = append(errors, err.Error())
477489
}
478-
glog.Infof("Deleting machine sets")
490+
glog.Infof("Deleting machine sets in namespace %q", namespace)
479491
if err := client.DeleteMachineSetObjectsInNamespace(namespace); err != nil {
480492
err = fmt.Errorf("error deleting machine sets: %v", err)
481493
errors = append(errors, err.Error())
482494
}
483-
glog.Infof("Deleting machines")
495+
glog.Infof("Deleting machines in namespace %q", namespace)
484496
if err := client.DeleteMachineObjectsInNamespace(namespace); err != nil {
485497
err = fmt.Errorf("error deleting machines: %v", err)
486498
errors = append(errors, err.Error())
487499
}
488-
glog.Infof("Deleting clusters")
500+
glog.Infof("Deleting clusters in namespace %q", namespace)
489501
if err := client.DeleteClusterObjectsInNamespace(namespace); err != nil {
490502
err = fmt.Errorf("error deleting clusters: %v", err)
491503
errors = append(errors, err.Error())
492504
}
505+
glog.Infof("Deleting namespace %q", namespace)
506+
if err := client.DeleteNamespace(namespace); err != nil {
507+
err = fmt.Errorf("error deleting namespace: %v", err)
508+
errors = append(errors, err.Error())
509+
}
493510
if len(errors) > 0 {
494511
return fmt.Errorf("error(s) encountered deleting objects from bootstrap cluster: [%v]", strings.Join(errors, ", "))
495512
}

clusterctl/clusterdeployer/clusterdeployer_test.go

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,15 @@ type testClusterClient struct {
108108
DeleteMachineDeploymentsObjectsErr error
109109
DeleteMachineDeploymentsObjectsInNamespaceErr error
110110
UpdateClusterObjectEndpointErr error
111+
EnsureNamespaceErr error
112+
DeleteNamespaceErr error
111113
CloseErr error
112114

113115
clusters map[string][]*clusterv1.Cluster
114116
machineDeployments map[string][]*clusterv1.MachineDeployment
115117
machineSets map[string][]*clusterv1.MachineSet
116118
machines map[string][]*clusterv1.Machine
119+
namespaces []string
117120
contextNamespace string
118121
}
119122

@@ -280,6 +283,40 @@ func (c *testClusterClient) Close() error {
280283
return c.CloseErr
281284
}
282285

286+
func (c *testClusterClient) EnsureNamespace(nsName string) error {
287+
if len(c.namespaces) == 0 {
288+
c.namespaces = append(c.namespaces, nsName)
289+
}
290+
if exists := contains(c.namespaces, nsName); !exists {
291+
c.namespaces = append(c.namespaces, nsName)
292+
}
293+
return c.EnsureNamespaceErr
294+
}
295+
296+
func (c *testClusterClient) DeleteNamespace(namespaceName string) error {
297+
var ns []string
298+
for _, n := range c.namespaces {
299+
if n == namespaceName {
300+
continue
301+
}
302+
ns = append(ns, n)
303+
}
304+
c.namespaces = ns
305+
306+
return c.DeleteNamespaceErr
307+
}
308+
309+
func contains(s []string, e string) bool {
310+
exists := false
311+
for _, existingNs := range s {
312+
if existingNs == e {
313+
exists = true
314+
break
315+
}
316+
}
317+
return exists
318+
}
319+
283320
type testClusterClientFactory struct {
284321
ClusterClientErr error
285322
clusterClients map[string]*testClusterClient
@@ -401,6 +438,28 @@ func TestClusterCreate(t *testing.T) {
401438
},
402439
expectedTotalInternalClustersCount: 1,
403440
},
441+
{
442+
name: "fail ensureNamespace in bootstrap cluster",
443+
targetClient: &testClusterClient{},
444+
bootstrapClient: &testClusterClient{EnsureNamespaceErr: fmt.Errorf("Test failure")},
445+
namespaceToExpectedInternalMachines: make(map[string]int),
446+
namespaceToInputCluster: map[string][]*clusterv1.Cluster{"foo": getClustersForNamespace("foo", 3)},
447+
expectErr: true,
448+
cleanupExternal: true,
449+
expectExternalExists: false,
450+
expectExternalCreated: true,
451+
},
452+
{
453+
name: "fail ensureNamespace in target cluster",
454+
targetClient: &testClusterClient{EnsureNamespaceErr: fmt.Errorf("Test failure")},
455+
bootstrapClient: &testClusterClient{},
456+
namespaceToExpectedInternalMachines: make(map[string]int),
457+
namespaceToInputCluster: map[string][]*clusterv1.Cluster{"foo": getClustersForNamespace("foo", 3)},
458+
expectErr: true,
459+
cleanupExternal: true,
460+
expectExternalExists: false,
461+
expectExternalCreated: true,
462+
},
404463
{
405464
name: "fail provision multiple clusters in a namespace",
406465
targetClient: &testClusterClient{},
@@ -564,7 +623,6 @@ func TestClusterCreate(t *testing.T) {
564623
}
565624

566625
for _, testcase := range testcases {
567-
568626
t.Run(testcase.name, func(t *testing.T) {
569627
kubeconfigOut := newTempFile(t)
570628
defer os.Remove(kubeconfigOut)
@@ -637,6 +695,14 @@ func TestClusterCreate(t *testing.T) {
637695
t.Fatalf("Unexpected machine name at %v in namespace %q. Got: %v, Want: %v", i, ns, inputMachines[i].Name, testcase.targetClient.machines[ns][i].Name)
638696
}
639697
}
698+
699+
if !contains(testcase.targetClient.namespaces, ns) {
700+
t.Fatalf("Expected namespace %q in target namespace not found. Got: NotFound, Want: Found", ns)
701+
}
702+
703+
if !contains(testcase.bootstrapClient.namespaces, ns) {
704+
t.Fatalf("Expected namespace %q in bootstrap namespace not found. Got: NotFound, Want: Found", ns)
705+
}
640706
}
641707
// Validate across all namespaces
642708
if len(testcase.targetClient.clusters) != testcase.expectedTotalInternalClustersCount {
@@ -800,7 +866,7 @@ func TestDeleteCleanupExternalCluster(t *testing.T) {
800866
}
801867
}
802868

803-
func TestDeleteClusters(t *testing.T) {
869+
func TestClusterDelete(t *testing.T) {
804870
const bootstrapKubeconfig = "bootstrap"
805871
const targetKubeconfig = "target"
806872

@@ -1101,10 +1167,15 @@ func TestDeleteClusters(t *testing.T) {
11011167
if len(testCase.bootstrapClient.machineDeployments[testCase.namespace]) != 0 {
11021168
t.Fatalf("Unexpected machineDeployments count in namespace %q. Got: %d, Want: 0", testCase.namespace, len(testCase.targetClient.machineDeployments[testCase.namespace]))
11031169
}
1104-
11051170
if len(testCase.bootstrapClient.clusters) != testCase.expectedExternalClusterCount {
11061171
t.Fatalf("Unexpected remaining cluster count. Got: %d, Want: %d", len(testCase.bootstrapClient.clusters), testCase.expectedExternalClusterCount)
11071172
}
1173+
if contains(testCase.bootstrapClient.namespaces, testCase.namespace) {
1174+
t.Fatalf("Unexpected remaining namespace %q in bootstrap cluster. Got: Found, Want: NotFound", testCase.namespace)
1175+
}
1176+
if contains(testCase.targetClient.namespaces, testCase.namespace) {
1177+
t.Fatalf("Unexpected remaining namespace %q in target cluster. Got: Found, Want: NotFound", testCase.namespace)
1178+
}
11081179
}
11091180
})
11101181
}

0 commit comments

Comments
 (0)