-
Notifications
You must be signed in to change notification settings - Fork 2
/
namespaces.go
139 lines (115 loc) · 4.03 KB
/
namespaces.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package kube
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/rs/zerolog/log"
corev1 "k8s.io/api/core/v1"
k8errs "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
)
const waitTimeout = 15 * time.Second
// ApplyNamespace Creates a new namespace, if not exists already
func (kubeutil *Kube) ApplyNamespace(name string, labels map[string]string, ownerRefs []metav1.OwnerReference) error {
log.Debug().Msgf("Create namespace: %s", name)
namespace := corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: name,
OwnerReferences: ownerRefs,
Labels: labels,
},
}
oldNamespace, err := kubeutil.getNamespace(name)
if err != nil && k8errs.IsNotFound(err) {
log.Debug().Msgf("namespace object %s doesn't exists, create the object", name)
_, err := kubeutil.kubeClient.CoreV1().Namespaces().Create(context.TODO(), &namespace, metav1.CreateOptions{})
return err
}
newNamespace := oldNamespace.DeepCopy()
newNamespace.ObjectMeta.OwnerReferences = ownerRefs
newNamespace.ObjectMeta.Labels = labels
oldNamespaceJSON, err := json.Marshal(oldNamespace)
if err != nil {
return fmt.Errorf("failed to marshal old namespace object: %v", err)
}
newNamespaceJSON, err := json.Marshal(newNamespace)
if err != nil {
return fmt.Errorf("failed to marshal new namespace object: %v", err)
}
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldNamespaceJSON, newNamespaceJSON, corev1.Namespace{})
if err != nil {
return fmt.Errorf("failed to create two way merge patch namespace objects: %v", err)
}
if !IsEmptyPatch(patchBytes) {
patchedNamespace, err := kubeutil.kubeClient.CoreV1().Namespaces().Patch(context.TODO(), name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{})
if err != nil {
return fmt.Errorf("failed to patch namespace object: %v", err)
}
log.Debug().Msgf("Patched namespace: %s ", patchedNamespace.Name)
return nil
}
log.Debug().Msgf("No need to patch namespace: %s ", name)
return nil
}
func (kubeutil *Kube) getNamespace(name string) (*corev1.Namespace, error) {
var namespace *corev1.Namespace
var err error
if kubeutil.NamespaceLister != nil {
namespace, err = kubeutil.NamespaceLister.Get(name)
if err != nil {
return nil, err
}
} else {
namespace, err = kubeutil.kubeClient.CoreV1().Namespaces().Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return nil, err
}
}
return namespace, nil
}
// NamespaceWatcher Watcher to wait for namespace to be created
type NamespaceWatcher interface {
WaitFor(namespace string) error
}
// NamespaceWatcherImpl Implementation of watcher
type NamespaceWatcherImpl struct {
client kubernetes.Interface
}
// NewNamespaceWatcherImpl Constructor
func NewNamespaceWatcherImpl(client kubernetes.Interface) NamespaceWatcherImpl {
return NamespaceWatcherImpl{
client,
}
}
// WaitFor Waits for namespace to appear
func (watcher NamespaceWatcherImpl) WaitFor(namespace string) error {
log.Info().Msgf("Waiting for namespace %s", namespace)
err := waitForNamespace(watcher.client, namespace)
if err != nil {
return err
}
log.Info().Msgf("Namespace %s exists and is active", namespace)
return nil
}
func waitForNamespace(client kubernetes.Interface, namespace string) error {
timoutContext, cancel := context.WithTimeout(context.Background(), waitTimeout)
defer cancel()
return wait.PollUntilContextCancel(timoutContext, time.Second, true, func(ctx context.Context) (done bool, err error) {
ns, err := client.CoreV1().Namespaces().Get(context.TODO(), namespace, metav1.GetOptions{})
if err != nil {
if k8errs.IsNotFound(err) || k8errs.IsForbidden(err) {
return false, nil // the environment namespace or the rolebinding for the cluster-role radix-pipeline-env are not yet created
}
return false, err
}
if ns != nil && ns.Status.Phase == corev1.NamespaceActive {
return true, nil
}
return false, nil
})
}