/
namespaceManager.go
116 lines (105 loc) · 3.2 KB
/
namespaceManager.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
package k8s
import (
"log"
"strings"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
utils "github.com/SAP/stewardci-core/pkg/utils"
)
//NamespaceManager manages namespaces
type NamespaceManager interface {
Create(name string, annotations map[string]string) (string, error)
Delete(name string) error
}
type namespaceManager struct {
nsInterface corev1.NamespaceInterface
prefix string
suffixLength uint8
}
// NewNamespaceManager creates a new NamespaceManager.
func NewNamespaceManager(factory ClientFactory, prefix string, suffixLength uint8) NamespaceManager {
return &namespaceManager{
nsInterface: factory.CoreV1().Namespaces(),
prefix: prefix,
suffixLength: suffixLength,
}
}
const (
labelPrefix = "prefix"
labelID = "id"
)
//Create creates a new namespace.
// nameCustomPart the namespace name will be <prefix>-<nameCustomPart>-<random>
// annotations annotations to create on the namespace
func (m *namespaceManager) Create(nameCustomPart string, annotations map[string]string) (string, error) {
name, err := m.generateName(nameCustomPart)
if err != nil {
log.Printf("Namespace creation failed %s", err)
return "", err
}
meta := metav1.ObjectMeta{
Name: name,
Labels: map[string]string{
labelPrefix: m.prefix,
labelID: nameCustomPart,
},
Annotations: annotations,
}
namespace := &v1.Namespace{ObjectMeta: meta}
createdNamespace, err := m.nsInterface.Create(namespace)
if err != nil {
log.Printf("Namespace creation failed: %s", err)
return "", err
}
log.Printf("Namespace '%s' created", createdNamespace.GetName())
return createdNamespace.GetName(), nil
}
// Delete removes a namespace if existing
// returns nil error if deletion was successful or namespace did not exist before
func (m *namespaceManager) Delete(name string) error {
if !strings.HasPrefix(name, m.prefix) {
return errors.Errorf("refused to delete namespace '%s': name does not start with '%s'", name, m.prefix)
}
namespace, err := m.nsInterface.Get(name, metav1.GetOptions{})
if err != nil {
if k8serrors.IsNotFound(err) {
return nil
}
return errors.WithMessagef(err, "error getting namespace '%s'", name)
}
if namespace.GetLabels()[labelPrefix] != m.prefix {
return errors.Errorf("refused to delete namespace '%s': not a Steward namespace (label mismatch)", name)
}
uid := namespace.GetObjectMeta().GetUID()
err = m.nsInterface.Delete(name, &metav1.DeleteOptions{
Preconditions: &metav1.Preconditions{UID: &uid},
})
if err != nil {
if k8serrors.IsNotFound(err) {
return nil
}
return errors.WithMessagef(err, "error deleting namespace '%s'", name)
}
log.Printf("deleted namespace '%s'", name)
return nil
}
func (m *namespaceManager) generateName(customPart string) (string, error) {
parts := []string{}
if m.prefix != "" {
parts = append(parts, m.prefix)
}
if customPart != "" {
parts = append(parts, customPart)
}
suffix, err := utils.RandomAlphaNumString(int64(m.suffixLength))
if err != nil {
return "", err
}
if suffix != "" {
parts = append(parts, suffix)
}
return strings.Join(parts, "-"), nil
}