Skip to content

Support cluster API objects in multiple namespaces #481

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clusterctl/clusterdeployer/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ go_library(
"//pkg/util:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
Expand Down
196 changes: 145 additions & 51 deletions clusterctl/clusterdeployer/clusterclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"time"

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

func (c *clusterClient) EnsureNamespace(namespaceName string) error {
clientset, err := clientcmd.NewCoreClientSetForKubeconfig(c.kubeconfigFile)
if err != nil {
return fmt.Errorf("error creating core clientset: %v", err)
}

namespace := apiv1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespaceName,
},
}
_, err = clientset.CoreV1().Namespaces().Create(&namespace)
if err != nil && !apierrors.IsAlreadyExists(err) {
return err
}
return nil
}

func (c *clusterClient) DeleteNamespace(namespaceName string) error {
clientset, err := clientcmd.NewCoreClientSetForKubeconfig(c.kubeconfigFile)
if err != nil {
return fmt.Errorf("error creating core clientset: %v", err)
}

err = clientset.CoreV1().Namespaces().Delete(namespaceName, &metav1.DeleteOptions{})
if err != nil && !apierrors.IsNotFound(err) {
return err
}
return nil
}

// NewClusterClientFromDefaultSearchPath creates and returns the address of a clusterClient, the kubeconfigFile argument is expected to be the path to a
// valid kubeconfig file.
func NewClusterClientFromDefaultSearchPath(kubeconfigFile string, overrides tcmd.ConfigOverrides) (*clusterClient, error) {
Expand Down Expand Up @@ -104,12 +136,33 @@ func (c *clusterClient) Apply(manifest string) error {
return c.waitForKubectlApply(manifest)
}

func (c *clusterClient) GetClusterObjects() ([]*clusterv1.Cluster, error) {
func (c *clusterClient) GetContextNamespace() string {
if c.configOverrides.Context.Namespace == "" {
c.configOverrides.Context.Namespace = apiv1.NamespaceDefault
}
return c.configOverrides.Context.Namespace
}

func (c *clusterClient) GetClusterObject(name, ns string) (*clusterv1.Cluster, error) {
clustersInNamespace, err := c.GetClusterObjectsInNamespace(ns)
if err != nil {
return nil, err
}
var cluster *clusterv1.Cluster
for _, nc := range clustersInNamespace {
if nc.Name == name {
cluster = nc
break
}
}
return cluster, nil
}

func (c *clusterClient) GetClusterObjectsInNamespace(namespace string) ([]*clusterv1.Cluster, error) {
clusters := []*clusterv1.Cluster{}
// TODO: Iterate over all namespaces where we could have Cluster API Objects https://github.com/kubernetes-sigs/cluster-api/issues/252
clusterlist, err := c.clientSet.ClusterV1alpha1().Clusters(apiv1.NamespaceDefault).List(metav1.ListOptions{})
clusterlist, err := c.clientSet.ClusterV1alpha1().Clusters(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, fmt.Errorf("error listing cluster objects: %v", err)
return nil, fmt.Errorf("error listing cluster objects in namespace %q: %v", namespace, err)
}

for i := 0; i < len(clusterlist.Items); i++ {
Expand All @@ -118,11 +171,16 @@ func (c *clusterClient) GetClusterObjects() ([]*clusterv1.Cluster, error) {
return clusters, nil
}

func (c *clusterClient) GetMachineDeploymentObjects() ([]*clusterv1.MachineDeployment, error) {
// TODO: Iterate over all namespaces where we could have Cluster API Objects https://github.com/kubernetes-sigs/cluster-api/issues/252
machineDeploymentList, err := c.clientSet.ClusterV1alpha1().MachineDeployments(apiv1.NamespaceDefault).List(metav1.ListOptions{})
// Deprecated API. Please do not extend or use.
func (c *clusterClient) GetClusterObjects() ([]*clusterv1.Cluster, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add comments to these preserved methods to indicate that they are deprecated and to be removed in the future? It might be good to also log the deprecation as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion. Added comments and log messages.

glog.V(2).Info("GetClusterObjects API is deprecated, use GetClusterObjectsInNamespace instead")
return c.GetClusterObjectsInNamespace(apiv1.NamespaceDefault)
}

func (c *clusterClient) GetMachineDeploymentObjectsInNamespace(namespace string) ([]*clusterv1.MachineDeployment, error) {
machineDeploymentList, err := c.clientSet.ClusterV1alpha1().MachineDeployments(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, fmt.Errorf("error listing machine deployment objects: %v", err)
return nil, fmt.Errorf("error listing machine deployment objects in namespace %q: %v", namespace, err)
}
var machineDeployments []*clusterv1.MachineDeployment
for i := 0; i < len(machineDeploymentList.Items); i++ {
Expand All @@ -131,11 +189,16 @@ func (c *clusterClient) GetMachineDeploymentObjects() ([]*clusterv1.MachineDeplo
return machineDeployments, nil
}

func (c *clusterClient) GetMachineSetObjects() ([]*clusterv1.MachineSet, error) {
// TODO: Iterate over all namespaces where we could have Cluster API Objects https://github.com/kubernetes-sigs/cluster-api/issues/252
// Deprecated API. Please do not extend or use.
func (c *clusterClient) GetMachineDeploymentObjects() ([]*clusterv1.MachineDeployment, error) {
glog.V(2).Info("GetMachineDeploymentObjects API is deprecated, use GetMachineDeploymentObjectsInNamespace instead")
return c.GetMachineDeploymentObjectsInNamespace(apiv1.NamespaceDefault)
}

func (c *clusterClient) GetMachineSetObjectsInNamespace(namespace string) ([]*clusterv1.MachineSet, error) {
machineSetList, err := c.clientSet.ClusterV1alpha1().MachineSets(apiv1.NamespaceDefault).List(metav1.ListOptions{})
if err != nil {
return nil, fmt.Errorf("error listing machine set objects: %v", err)
return nil, fmt.Errorf("error listing machine set objects in namespace %q: %v", namespace, err)
}
var machineSets []*clusterv1.MachineSet
for i := 0; i < len(machineSetList.Items); i++ {
Expand All @@ -144,12 +207,17 @@ func (c *clusterClient) GetMachineSetObjects() ([]*clusterv1.MachineSet, error)
return machineSets, nil
}

func (c *clusterClient) GetMachineObjects() ([]*clusterv1.Machine, error) {
// TODO: Iterate over all namespaces where we could have Cluster API Objects https://github.com/kubernetes-sigs/cluster-api/issues/252
// Deprecated API. Please do not extend or use.
func (c *clusterClient) GetMachineSetObjects() ([]*clusterv1.MachineSet, error) {
glog.V(2).Info("GetMachineSetObjects API is deprecated, use GetMachineSetObjectsInNamespace instead")
return c.GetMachineSetObjectsInNamespace(apiv1.NamespaceDefault)
}

func (c *clusterClient) GetMachineObjectsInNamespace(namespace string) ([]*clusterv1.Machine, error) {
machines := []*clusterv1.Machine{}
machineslist, err := c.clientSet.ClusterV1alpha1().Machines(apiv1.NamespaceDefault).List(metav1.ListOptions{})
machineslist, err := c.clientSet.ClusterV1alpha1().Machines(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, fmt.Errorf("error listing machine objects: %v", err)
return nil, fmt.Errorf("error listing machine objects in namespace %q: %v", namespace, err)
}

for i := 0; i < len(machineslist.Items); i++ {
Expand All @@ -158,46 +226,53 @@ func (c *clusterClient) GetMachineObjects() ([]*clusterv1.Machine, error) {
return machines, nil
}

// Deprecated API. Please do not extend or use.
func (c *clusterClient) GetMachineObjects() ([]*clusterv1.Machine, error) {
glog.V(2).Info("GetMachineObjects API is deprecated, use GetMachineObjectsInNamespace instead")
return c.GetMachineObjectsInNamespace(apiv1.NamespaceDefault)
}

func (c *clusterClient) CreateClusterObject(cluster *clusterv1.Cluster) error {
// TODO: Support specific namespaces https://github.com/kubernetes-sigs/cluster-api/issues/252
_, err := c.clientSet.ClusterV1alpha1().Clusters(apiv1.NamespaceDefault).Create(cluster)
namespace := c.GetContextNamespace()
if cluster.Namespace != "" {
namespace = cluster.Namespace
}

_, err := c.clientSet.ClusterV1alpha1().Clusters(namespace).Create(cluster)
if err != nil {
return fmt.Errorf("error creating cluster: %v", err)
return fmt.Errorf("error creating cluster in namespace %v: %v", namespace, err)
}
return err
}

func (c *clusterClient) CreateMachineDeploymentObjects(deployments []*clusterv1.MachineDeployment) error {
// TODO: Support specific namespaces https://github.com/kubernetes-sigs/cluster-api/issues/252
func (c *clusterClient) CreateMachineDeploymentObjects(deployments []*clusterv1.MachineDeployment, namespace string) error {
for _, deploy := range deployments {
// TODO: Run in parallel https://github.com/kubernetes-sigs/cluster-api/issues/258
_, err := c.clientSet.ClusterV1alpha1().MachineDeployments(apiv1.NamespaceDefault).Create(deploy)
_, err := c.clientSet.ClusterV1alpha1().MachineDeployments(namespace).Create(deploy)
if err != nil {
return fmt.Errorf("error creating a machine deployment object: %v", err)
return fmt.Errorf("error creating a machine deployment object in namespace %q: %v", namespace, err)
}
}
return nil
}

func (c *clusterClient) CreateMachineSetObjects(machineSets []*clusterv1.MachineSet) error {
// TODO: Support specific namespaces https://github.com/kubernetes-sigs/cluster-api/issues/252
func (c *clusterClient) CreateMachineSetObjects(machineSets []*clusterv1.MachineSet, namespace string) error {
for _, ms := range machineSets {
// TODO: Run in parallel https://github.com/kubernetes-sigs/cluster-api/issues/258
_, err := c.clientSet.ClusterV1alpha1().MachineSets(apiv1.NamespaceDefault).Create(ms)
_, err := c.clientSet.ClusterV1alpha1().MachineSets(namespace).Create(ms)
if err != nil {
return fmt.Errorf("error creating a machine set object: %v", err)
return fmt.Errorf("error creating a machine set object in namespace %q: %v", namespace, err)
}
}
return nil
}

func (c *clusterClient) CreateMachineObjects(machines []*clusterv1.Machine) error {
// TODO: Support specific namespaces https://github.com/kubernetes-sigs/cluster-api/issues/252
func (c *clusterClient) CreateMachineObjects(machines []*clusterv1.Machine, namespace string) error {
for _, machine := range machines {
// TODO: Run in parallel https://github.com/kubernetes-sigs/cluster-api/issues/258
createdMachine, err := c.clientSet.ClusterV1alpha1().Machines(apiv1.NamespaceDefault).Create(machine)
createdMachine, err := c.clientSet.ClusterV1alpha1().Machines(namespace).Create(machine)
if err != nil {
return fmt.Errorf("error creating a machine object: %v", err)
return fmt.Errorf("error creating a machine object in namespace %v: %v", namespace, err)
}
err = waitForMachineReady(c.clientSet, createdMachine)
if err != nil {
Expand All @@ -207,71 +282,90 @@ func (c *clusterClient) CreateMachineObjects(machines []*clusterv1.Machine) erro
return nil
}

// Deprecated API. Please do not extend or use.
func (c *clusterClient) DeleteClusterObjects() error {
err := c.clientSet.ClusterV1alpha1().Clusters(apiv1.NamespaceDefault).DeleteCollection(newDeleteOptions(), metav1.ListOptions{})
glog.V(2).Info("DeleteClusterObjects API is deprecated, use DeleteClusterObjectsInNamespace instead")
return c.DeleteClusterObjectsInNamespace(apiv1.NamespaceDefault)
}

func (c *clusterClient) DeleteClusterObjectsInNamespace(namespace string) error {
err := c.clientSet.ClusterV1alpha1().Clusters(namespace).DeleteCollection(newDeleteOptions(), metav1.ListOptions{})
if err != nil {
return fmt.Errorf("error deleting cluster objects: %v", err)
return fmt.Errorf("error deleting cluster objects in namespace %q: %v", namespace, err)
}
err = c.waitForClusterDelete()
if err != nil {
return fmt.Errorf("error waiting for cluster(s) deletion to complete: %v", err)
return fmt.Errorf("error waiting for cluster(s) deletion to complete in namespace %q: %v", namespace, err)
}
return nil
}

// Deprecated API. Please do not extend or use.
func (c *clusterClient) DeleteMachineDeploymentObjects() error {
err := c.clientSet.ClusterV1alpha1().MachineDeployments(apiv1.NamespaceDefault).DeleteCollection(newDeleteOptions(), metav1.ListOptions{})
glog.V(2).Info("DeleteMachineDeploymentObjects API is deprecated, use DeleteMachineDeploymentObjectsInNamespace instead")
return c.DeleteMachineDeploymentObjectsInNamespace(apiv1.NamespaceDefault)
}

func (c *clusterClient) DeleteMachineDeploymentObjectsInNamespace(namespace string) error {
err := c.clientSet.ClusterV1alpha1().MachineDeployments(namespace).DeleteCollection(newDeleteOptions(), metav1.ListOptions{})
if err != nil {
return fmt.Errorf("error deleting machine deployment objects: %v", err)
return fmt.Errorf("error deleting machine deployment objects in namespace %q: %v", namespace, err)
}
err = c.waitForMachineDeploymentsDelete()
if err != nil {
return fmt.Errorf("error waiting for machine deployment(s) deletion to complete: %v", err)
return fmt.Errorf("error waiting for machine deployment(s) deletion to complete in namespace %q: %v", namespace, err)
}
return nil
}

// Deprecated API. Please do not extend or use.
func (c *clusterClient) DeleteMachineSetObjects() error {
err := c.clientSet.ClusterV1alpha1().MachineSets(apiv1.NamespaceDefault).DeleteCollection(newDeleteOptions(), metav1.ListOptions{})
glog.V(2).Info("DeleteMachineSetObjects API is deprecated, use DeleteMachineSetObjectsInNamespace instead")
return c.DeleteMachineSetObjectsInNamespace(apiv1.NamespaceDefault)
}

func (c *clusterClient) DeleteMachineSetObjectsInNamespace(namespace string) error {
err := c.clientSet.ClusterV1alpha1().MachineSets(namespace).DeleteCollection(newDeleteOptions(), metav1.ListOptions{})
if err != nil {
return fmt.Errorf("error deleting machine set objects: %v", err)
return fmt.Errorf("error deleting machine set objects in namespace %q: %v", namespace, err)
}
err = c.waitForMachineSetsDelete()
if err != nil {
return fmt.Errorf("error waiting for machine set(s) deletion to complete: %v", err)
return fmt.Errorf("error waiting for machine set(s) deletion to complete in namespace %q: %v", namespace, err)
}
return nil
}

// Deprecated API. Please do not extend or use.
func (c *clusterClient) DeleteMachineObjects() error {
err := c.clientSet.ClusterV1alpha1().Machines(apiv1.NamespaceDefault).DeleteCollection(newDeleteOptions(), metav1.ListOptions{})
glog.V(2).Info("DeleteMachineObjects API is deprecated, use DeleteMachineObjectsInNamespace instead")
return c.DeleteMachineObjectsInNamespace(apiv1.NamespaceDefault)
}

func (c *clusterClient) DeleteMachineObjectsInNamespace(namespace string) error {
err := c.clientSet.ClusterV1alpha1().Machines(namespace).DeleteCollection(newDeleteOptions(), metav1.ListOptions{})
if err != nil {
return fmt.Errorf("error deleting machine objects: %v", err)
return fmt.Errorf("error deleting machine objects in namespace %q: %v", namespace, err)
}
err = c.waitForMachinesDelete()
if err != nil {
return fmt.Errorf("error waiting for machine(s) deletion to complete: %v", err)
return fmt.Errorf("error waiting for machine(s) deletion to complete in namespace %q: %v", namespace, err)
}
return nil
}

func newDeleteOptions() *metav1.DeleteOptions {
propogationPolicy := metav1.DeletePropagationForeground
propagationPolicy := metav1.DeletePropagationForeground
return &metav1.DeleteOptions{
PropagationPolicy: &propogationPolicy,
PropagationPolicy: &propagationPolicy,
}
}

func (c *clusterClient) UpdateClusterObjectEndpoint(masterIP string) error {
clusters, err := c.GetClusterObjects()
func (c *clusterClient) UpdateClusterObjectEndpoint(masterIP, clusterName, ns string) error {
cluster, err := c.GetClusterObject(clusterName, ns)
if err != nil {
return err
}
if len(clusters) != 1 {
// TODO: Do not assume default namespace nor single cluster https://github.com/kubernetes-sigs/cluster-api/issues/252
return fmt.Errorf("More than the one expected cluster found %v", clusters)
}
cluster := clusters[0]
cluster.Status.APIEndpoints = append(cluster.Status.APIEndpoints,
clusterv1.APIEndpoint{
Host: masterIP,
Expand Down
Loading