2021-08-26 14:00:59 +00:00
|
|
|
package cli
|
|
|
|
|
|
|
|
import (
|
2021-10-12 02:32:14 +00:00
|
|
|
"context"
|
2022-09-21 04:49:42 +00:00
|
|
|
"fmt"
|
2021-08-26 14:00:59 +00:00
|
|
|
"strconv"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
2022-09-21 04:49:42 +00:00
|
|
|
portainer "github.com/portainer/portainer/api"
|
2022-11-13 19:33:57 +00:00
|
|
|
models "github.com/portainer/portainer/api/http/models/kubernetes"
|
2021-08-26 14:00:59 +00:00
|
|
|
v1 "k8s.io/api/core/v1"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
systemNamespaceLabel = "io.portainer.kubernetes.namespace.system"
|
|
|
|
)
|
|
|
|
|
|
|
|
func defaultSystemNamespaces() map[string]struct{} {
|
|
|
|
return map[string]struct{}{
|
|
|
|
"kube-system": {},
|
|
|
|
"kube-public": {},
|
|
|
|
"kube-node-lease": {},
|
|
|
|
"portainer": {},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-21 04:49:42 +00:00
|
|
|
// GetNamespaces gets the namespaces in the current k8s environment(endpoint).
|
|
|
|
func (kcl *KubeClient) GetNamespaces() (map[string]portainer.K8sNamespaceInfo, error) {
|
|
|
|
namespaces, err := kcl.cli.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
results := make(map[string]portainer.K8sNamespaceInfo)
|
|
|
|
|
|
|
|
for _, ns := range namespaces.Items {
|
|
|
|
results[ns.Name] = portainer.K8sNamespaceInfo{
|
|
|
|
IsSystem: isSystemNamespace(ns),
|
|
|
|
IsDefault: ns.Name == defaultNamespace,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return results, nil
|
|
|
|
}
|
|
|
|
|
2022-10-27 03:14:54 +00:00
|
|
|
// GetNamespace gets the namespace in the current k8s environment(endpoint).
|
|
|
|
func (kcl *KubeClient) GetNamespace(name string) (portainer.K8sNamespaceInfo, error) {
|
|
|
|
namespace, err := kcl.cli.CoreV1().Namespaces().Get(context.TODO(), name, metav1.GetOptions{})
|
|
|
|
if err != nil {
|
|
|
|
return portainer.K8sNamespaceInfo{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
result := portainer.K8sNamespaceInfo{
|
|
|
|
IsSystem: isSystemNamespace(*namespace),
|
|
|
|
IsDefault: namespace.Name == defaultNamespace,
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
2022-12-20 03:46:51 +00:00
|
|
|
// CreateNamespace creates a new ingress in a given namespace in a k8s endpoint.
|
2022-09-26 19:43:24 +00:00
|
|
|
func (kcl *KubeClient) CreateNamespace(info models.K8sNamespaceDetails) error {
|
2022-09-21 04:49:42 +00:00
|
|
|
client := kcl.cli.CoreV1().Namespaces()
|
|
|
|
|
|
|
|
var ns v1.Namespace
|
|
|
|
ns.Name = info.Name
|
|
|
|
ns.Annotations = info.Annotations
|
|
|
|
|
|
|
|
_, err := client.Create(context.Background(), &ns, metav1.CreateOptions{})
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-08-26 14:00:59 +00:00
|
|
|
func isSystemNamespace(namespace v1.Namespace) bool {
|
|
|
|
systemLabelValue, hasSystemLabel := namespace.Labels[systemNamespaceLabel]
|
|
|
|
if hasSystemLabel {
|
|
|
|
return systemLabelValue == "true"
|
|
|
|
}
|
|
|
|
|
|
|
|
systemNamespaces := defaultSystemNamespaces()
|
|
|
|
|
|
|
|
_, isSystem := systemNamespaces[namespace.Name]
|
|
|
|
|
|
|
|
return isSystem
|
|
|
|
}
|
|
|
|
|
|
|
|
// ToggleSystemState will set a namespace as a system namespace, or remove this state
|
|
|
|
// if isSystem is true it will set `systemNamespaceLabel` to "true" and false otherwise
|
|
|
|
// this will skip if namespace is "default" or if the required state is already set
|
|
|
|
func (kcl *KubeClient) ToggleSystemState(namespaceName string, isSystem bool) error {
|
|
|
|
if namespaceName == "default" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
nsService := kcl.cli.CoreV1().Namespaces()
|
|
|
|
|
2021-10-12 02:32:14 +00:00
|
|
|
namespace, err := nsService.Get(context.TODO(), namespaceName, metav1.GetOptions{})
|
2021-08-26 14:00:59 +00:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed fetching namespace object")
|
|
|
|
}
|
|
|
|
|
|
|
|
if isSystemNamespace(*namespace) == isSystem {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if namespace.Labels == nil {
|
|
|
|
namespace.Labels = map[string]string{}
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace.Labels[systemNamespaceLabel] = strconv.FormatBool(isSystem)
|
|
|
|
|
2021-10-12 02:32:14 +00:00
|
|
|
_, err = nsService.Update(context.TODO(), namespace, metav1.UpdateOptions{})
|
2021-08-26 14:00:59 +00:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "failed updating namespace object")
|
|
|
|
}
|
|
|
|
|
|
|
|
if isSystem {
|
|
|
|
return kcl.NamespaceAccessPoliciesDeleteNamespace(namespaceName)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
}
|
2022-09-21 04:49:42 +00:00
|
|
|
|
|
|
|
// UpdateIngress updates an ingress in a given namespace in a k8s endpoint.
|
2022-09-26 19:43:24 +00:00
|
|
|
func (kcl *KubeClient) UpdateNamespace(info models.K8sNamespaceDetails) error {
|
2022-09-21 04:49:42 +00:00
|
|
|
client := kcl.cli.CoreV1().Namespaces()
|
|
|
|
|
|
|
|
var ns v1.Namespace
|
|
|
|
ns.Name = info.Name
|
|
|
|
ns.Annotations = info.Annotations
|
|
|
|
|
|
|
|
_, err := client.Update(context.Background(), &ns, metav1.UpdateOptions{})
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (kcl *KubeClient) DeleteNamespace(namespace string) error {
|
|
|
|
client := kcl.cli.CoreV1().Namespaces()
|
|
|
|
namespaces, err := client.List(context.Background(), metav1.ListOptions{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, ns := range namespaces.Items {
|
|
|
|
if ns.Name == namespace {
|
|
|
|
return client.Delete(
|
|
|
|
context.Background(),
|
|
|
|
namespace,
|
|
|
|
metav1.DeleteOptions{},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return fmt.Errorf("namespace %s not found", namespace)
|
|
|
|
}
|