Skip to content

Commit

Permalink
Refactor uninstaller to support new Liqo Authentication and peering
Browse files Browse the repository at this point in the history
  • Loading branch information
palexster committed Jul 6, 2021
1 parent 56813dd commit 95a0fa3
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 88 deletions.
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -77,7 +77,7 @@ rbacs: controller-gen
$(CONTROLLER_GEN) $(CRD_OPTIONS) paths="./pkg/liqo-controller-manager/..." rbac:roleName=liqo-controller-manager output:rbac:stdout | awk -v RS="---\n" 'NR>1{f="./deployments/liqo/files/liqo-controller-manager-" $$4 ".yaml";printf "%s",$$0 > f; close(f)}' && sed -i -n '/rules/,$$p' deployments/liqo/files/liqo-controller-manager-ClusterRole.yaml
$(CONTROLLER_GEN) $(CRD_OPTIONS) paths="./pkg/virtualKubelet/roles/local" rbac:roleName=liqo-virtual-kubelet-local output:rbac:stdout | awk -v RS="---\n" 'NR>1{f="./deployments/liqo/files/liqo-virtual-kubelet-local-" $$4 ".yaml";printf "%s",$$0 > f; close(f)}' && sed -i -n '/rules/,$$p' deployments/liqo/files/liqo-virtual-kubelet-local-ClusterRole.yaml
$(CONTROLLER_GEN) $(CRD_OPTIONS) paths="./pkg/virtualKubelet/roles/remote" rbac:roleName=liqo-virtual-kubelet-remote output:rbac:stdout | awk -v RS="---\n" 'NR>1{f="./deployments/liqo/files/liqo-virtual-kubelet-remote-" $$4 ".yaml";printf "%s",$$0 > f; close(f)}' && sed -i -n '/rules/,$$p' deployments/liqo/files/liqo-virtual-kubelet-remote-ClusterRole.yaml
$(CONTROLLER_GEN) $(CRD_OPTIONS) paths="./cmd/uninstaller" rbac:roleName=liqo-pre-delete output:rbac:stdout | awk -v RS="---\n" 'NR>1{f="./deployments/liqo/files/liqo-pre-delete-" $$4 ".yaml";printf "%s",$$0 > f; close(f)}' && sed -i -n '/rules/,$$p' deployments/liqo/files/liqo-pre-delete-ClusterRole.yaml deployments/liqo/files/liqo-pre-delete-Role.yaml
$(CONTROLLER_GEN) $(CRD_OPTIONS) paths="./cmd/uninstaller" rbac:roleName=liqo-pre-delete output:rbac:stdout | awk -v RS="---\n" 'NR>1{f="./deployments/liqo/files/liqo-pre-delete-" $$4 ".yaml";printf "%s",$$0 > f; close(f)}' && sed -i -n '/rules/,$$p' deployments/liqo/files/liqo-pre-delete-ClusterRole.yaml

# Install gci if not available
gci:
Expand Down
38 changes: 11 additions & 27 deletions cmd/uninstaller/main.go
Expand Up @@ -4,32 +4,28 @@ import (
"os"
"path/filepath"

"github.com/pkg/errors"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog/v2"

"github.com/liqotech/liqo/pkg/uninstaller"
"github.com/liqotech/liqo/pkg/utils"
)

// cluster-role
// +kubebuilder:rbac:groups=net.liqo.io,resources=tunnelendpoints,verbs=get;list;watch;
// +kubebuilder:rbac:groups=net.liqo.io,resources=networkconfigs,verbs=get;list;watch;
// +kubebuilder:rbac:groups=config.liqo.io,resources=clusterconfigs,verbs=get;list;watch;patch;update
// +kubebuilder:rbac:groups=core,resources=events,verbs=create;patch
// +kubebuilder:rbac:groups=discovery.liqo.io,resources=foreignclusters,verbs=get;list;watch;patch;update
// role
// +kubebuilder:rbac:groups=core,namespace="do-not-care",resources=pods,verbs=get;list;watch
// +kubebuilder:rbac:groups=discovery.liqo.io,resources=foreignclusters,verbs=get;list;watch;patch;update;delete;deletecollection;

func main() {
var config *rest.Config

kubeconfigPath, ok := os.LookupEnv("KUBECONFIG")
if !ok {
kubeconfigPath = filepath.Join(os.Getenv("HOME"), ".kube", "config")
}

klog.Infof("Loading dynamic client: %s", kubeconfigPath)
config, err := userConfig(kubeconfigPath)
config, err := utils.GetRestConfig(kubeconfigPath)
if err != nil {
klog.Errorf("Unable to create client config: %s", err)
os.Exit(1)
Expand All @@ -46,32 +42,20 @@ func main() {
}
klog.Info("Foreign Cluster unjoin operation has been correctly performed")

if err = uninstaller.DisableBroadcasting(client); err != nil {
klog.Errorf("Unable to deactivate outgoing resource sharing: %s", err)
if err = uninstaller.DisableDiscoveryAndPeering(client); err != nil {
klog.Errorf("Unable to deactivate discovery mechanism: %s", err)
os.Exit(1)
}

klog.Info("Outgoing Resource sharing has been disabled")

if err := uninstaller.WaitForResources(client); err != nil {
klog.Errorf("Unable to wait deletion of objects: %s", err)
os.Exit(1)
}
}

func userConfig(configPath string) (*rest.Config, error) {
var config *rest.Config
if _, err := os.Stat(configPath); !os.IsNotExist(err) {
// Get the kubeconfig from the filepath.
config, err = clientcmd.BuildConfigFromFlags("", configPath)
if err != nil {
return nil, errors.Wrap(err, "error building Client config")
}
} else {
// Set to in-cluster config.
config, err = rest.InClusterConfig()
if err != nil {
return nil, errors.Wrap(err, "error building in cluster config")
}
if err := uninstaller.DeleteAllForeignClusters(client); err != nil {
klog.Errorf("Unable to delete foreign clusters: %s", err)
os.Exit(1)
}
return config, nil
}
19 changes: 18 additions & 1 deletion deployments/liqo/files/liqo-pre-delete-ClusterRole.yaml
Expand Up @@ -21,9 +21,26 @@ rules:
resources:
- foreignclusters
verbs:
- delete
- deletecollection
- get
- list
- patch
- update
- watch

- apiGroups:
- net.liqo.io
resources:
- networkconfigs
verbs:
- get
- list
- watch
- apiGroups:
- net.liqo.io
resources:
- tunnelendpoints
verbs:
- get
- list
- watch
9 changes: 0 additions & 9 deletions deployments/liqo/files/liqo-pre-delete-Role.yaml

This file was deleted.

4 changes: 3 additions & 1 deletion deployments/liqo/templates/liqo-gateway-deployment.yaml
Expand Up @@ -8,6 +8,8 @@ metadata:
{{- include "liqo.labels" $gatewayConfig | nindent 4 }}
name: {{ include "liqo.prefixedName" $gatewayConfig }}
spec:
strategy:
type: Recreate
replicas: 1
selector:
matchLabels:
Expand Down Expand Up @@ -56,4 +58,4 @@ spec:
valueFrom:
fieldRef:
fieldPath: status.podIP
hostNetwork: true
hostNetwork: true
18 changes: 0 additions & 18 deletions deployments/liqo/templates/pre-delete-rbac.yaml
Expand Up @@ -10,24 +10,6 @@ metadata:
{{- include "liqo.preDeleteAnnotations" $predelete| nindent 4 }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "liqo.prefixedName" $predelete}}
namespace: {{ .Release.Namespace }}
labels:
{{- include "liqo.labels" $predelete| nindent 4 }}
annotations:
{{- include "liqo.preDeleteAnnotations" $predelete| nindent 4 }}
subjects:
- kind: ServiceAccount
name: {{ include "liqo.prefixedName" $predelete}}
namespace: {{ .Release.Namespace }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ include "liqo.prefixedName" $predelete}}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "liqo.prefixedName" $predelete}}
Expand Down
24 changes: 6 additions & 18 deletions pkg/uninstaller/const.go
Expand Up @@ -3,17 +3,19 @@ package uninstaller
import (
"time"

v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"

"github.com/liqotech/liqo/apis/net/v1alpha1"
peering_request_operator "github.com/liqotech/liqo/internal/peering-request-operator"
"github.com/liqotech/liqo/pkg/vkMachinery"
)

// TickerInterval defines the check interval.
const TickerInterval = 5 * time.Second
const TickerTimeout = 1 * time.Minute

// TickerTimeout defines the overall timeout to be waited.
const TickerTimeout = 5 * time.Minute

// ConditionsToCheck maps the number of conditions to be checked waiting for the unpeer.
const ConditionsToCheck = 1

type toCheckDeleted struct {
Expand All @@ -27,8 +29,6 @@ type resultType struct {
}

var (
podGVR = v1.SchemeGroupVersion.WithResource("pods")

toCheck = []toCheckDeleted{
{
gvr: v1alpha1.TunnelEndpointGroupVersionResource,
Expand All @@ -38,17 +38,5 @@ var (
gvr: v1alpha1.NetworkConfigGroupVersionResource,
labelSelector: metav1.LabelSelector{},
},
{
gvr: podGVR,
labelSelector: metav1.LabelSelector{
MatchLabels: vkMachinery.KubeletBaseLabels,
},
},
{
gvr: podGVR,
labelSelector: metav1.LabelSelector{
MatchLabels: peering_request_operator.BroadcasterBaseLabels,
},
},
}
)
82 changes: 70 additions & 12 deletions pkg/uninstaller/deletion.go
Expand Up @@ -2,7 +2,10 @@ package uninstaller

import (
"context"
"encoding/json"
"fmt"

"gomodules.xyz/jsonpatch/v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
Expand All @@ -21,20 +24,20 @@ func UnjoinClusters(client dynamic.Interface) error {
}
klog.Infof("Unjoin %v ForeignClusters", len(foreign.Items))
r1 := client.Resource(discoveryV1alpha1.ForeignClusterGroupVersionResource)
for _, item := range foreign.Items {
for index := range foreign.Items {
patch := []byte(`{"spec": {"join": false}}`)
_, err = r1.Namespace(item.Namespace).Patch(context.TODO(), item.Name, types.MergePatchType, patch, metav1.PatchOptions{})
_, err = r1.Patch(context.TODO(), foreign.Items[index].Name, types.MergePatchType, patch, metav1.PatchOptions{})
if err != nil {
return err
}
}
return nil
}

// DisableBroadcasting disables broadcasting of advertisements from the ClusterConfig.
func DisableBroadcasting(client dynamic.Interface) error {
// DisableDiscoveryAndPeering disables discovery and peering mechanism to prevent new peerings to happen.
func DisableDiscoveryAndPeering(client dynamic.Interface) error {
r1 := client.Resource(clusterconfigV1alpha1.ClusterConfigGroupVersionResource)
t, err := r1.Namespace("").List(context.TODO(), metav1.ListOptions{TypeMeta: metav1.TypeMeta{}})
t, err := r1.List(context.TODO(), metav1.ListOptions{TypeMeta: metav1.TypeMeta{}})
if err != nil {
return err
}
Expand All @@ -43,13 +46,68 @@ func DisableBroadcasting(client dynamic.Interface) error {
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(t.UnstructuredContent(), &clusterconfigs); err != nil {
return err
}
klog.V(5).Infof("Patching ClusterConfigs")
for _, item := range clusterconfigs.Items {
patch := []byte(`{"spec": {"advertisementConfig": { "outgoingConfig" : { "enableBroadcaster" : false}}}}`)
_, err = r1.Namespace(item.Namespace).Patch(context.TODO(), item.Name, types.MergePatchType, patch, metav1.PatchOptions{})
if err != nil {
return err
}
if len(clusterconfigs.Items) != 1 {
return fmt.Errorf("ERROR: Wrong number of ClusterConfig: %v", len(clusterconfigs.Items))
}
err = patchClusterConfig(forgeUninstallClusterConfig, &clusterconfigs.Items[0], client)
return err
}

// DeleteAllForeignClusters deletes all ForeignCluster resources.
func DeleteAllForeignClusters(client dynamic.Interface) error {
r1 := client.Resource(discoveryV1alpha1.ForeignClusterGroupVersionResource)
err := r1.DeleteCollection(context.TODO(),
metav1.DeleteOptions{TypeMeta: metav1.TypeMeta{}}, metav1.ListOptions{TypeMeta: metav1.TypeMeta{}})
return err
}

func forgeUninstallClusterConfig(clusterConfig *clusterconfigV1alpha1.ClusterConfig) {
clusterConfig.Spec.DiscoveryConfig.EnableDiscovery = false
clusterConfig.Spec.DiscoveryConfig.EnableAdvertisement = false
clusterConfig.Spec.AdvertisementConfig.OutgoingConfig.EnableBroadcaster = false
}

// patchClusterConfig patches the controlled ClusterConfig applying the provided function.
func patchClusterConfig(changeFunc func(node *clusterconfigV1alpha1.ClusterConfig),
initialClusterConfig *clusterconfigV1alpha1.ClusterConfig, client dynamic.Interface) error {
original, err := json.Marshal(initialClusterConfig)
if err != nil {
klog.Error(err)
return err
}

newClusterConfig := initialClusterConfig.DeepCopy()
changeFunc(newClusterConfig)

target, err := json.Marshal(newClusterConfig)
if err != nil {
klog.Error(err)
return err
}

ops, err := jsonpatch.CreatePatch(original, target)
if err != nil {
klog.Error(err)
return err
}

if len(ops) == 0 {
// this avoids an empty patch of the node
return nil
}

bytes, err := json.Marshal(ops)
if err != nil {
klog.Error(err)
return err
}

r1 := client.Resource(clusterconfigV1alpha1.ClusterConfigGroupVersionResource)
_, err = r1.Patch(context.TODO(), newClusterConfig.Name, types.JSONPatchType, bytes, metav1.PatchOptions{})
if err != nil {
klog.Error(err)
return err
}

return nil
}
2 changes: 1 addition & 1 deletion pkg/uninstaller/helpers.go
Expand Up @@ -28,7 +28,7 @@ func getForeignList(client dynamic.Interface) (*discoveryV1alpha1.ForeignCluster
return foreign, nil
}

// checkPeeringsStatus verifies if all clusters have not active peerings.
// checkPeeringsStatus verifies if the cluster has any active peerings with foreign clusters.
func checkPeeringsStatus(foreign *discoveryV1alpha1.ForeignClusterList) bool {
var returnValue = true
for i := range foreign.Items {
Expand Down
14 changes: 14 additions & 0 deletions pkg/utils/cluster_info.go
Expand Up @@ -11,6 +11,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog"
"sigs.k8s.io/controller-runtime/pkg/client"

Expand Down Expand Up @@ -67,3 +69,15 @@ func RetrieveNamespace() (string, error) {
}
return namespace, nil
}

// GetRestConfig returns a rest.Config object to initialize a client to the target cluster.
func GetRestConfig(configPath string) (config *rest.Config, err error) {
if _, err = os.Stat(configPath); err == nil {
// Get the kubeconfig from the filepath.
config, err = clientcmd.BuildConfigFromFlags("", configPath)
} else {
// Set to in-cluster config.
config, err = rest.InClusterConfig()
}
return config, err
}

0 comments on commit 95a0fa3

Please sign in to comment.