This commit is contained in:
mr
2025-04-28 14:39:53 +02:00
parent 3ae9f69525
commit cf92b46ce6
8 changed files with 88 additions and 95 deletions

View File

@@ -195,27 +195,25 @@ func (k *KubernetesService) GenerateToken(ctx context.Context, ns string, durati
return token.Status.Token, nil
}
// Needs refactoring :
// - Retrieving the metada (in a method that Unmarshall the part of the json in a metadata object)
func (k *KubernetesService) GetTargets(ctx context.Context) ([]string,error){
// - Retrieving the metada (in a method that Unmarshall the part of the json in a metadata object)
func (k *KubernetesService) GetTargets(ctx context.Context) ([]string, error) {
var listTargets []string
resp, err := getCDRapiKube(*k.Set, ctx,"/apis/multicluster.admiralty.io/v1alpha1/targets")
resp, err := getCDRapiKube(*k.Set, ctx, "/apis/multicluster.admiralty.io/v1alpha1/targets")
if err != nil {
return nil,err
return nil, err
}
fmt.Println(string(resp))
var targetDict map[string]interface{}
err = json.Unmarshal(resp,&targetDict)
err = json.Unmarshal(resp, &targetDict)
if err != nil {
fmt.Println("TODO: handle the error when unmarshalling k8s API response")
return nil, err
}
b, _ := json.MarshalIndent(targetDict,""," ")
b, _ := json.MarshalIndent(targetDict, "", " ")
fmt.Println(string(b))
data := targetDict["items"].([]interface{})
@@ -224,25 +222,25 @@ func (k *KubernetesService) GetTargets(ctx context.Context) ([]string,error){
var metadata metav1.ObjectMeta
item := item.(map[string]interface{})
byteMetada, err := json.Marshal(item["metadata"])
if err != nil {
fmt.Println("Error while Marshalling metadata field")
return nil,err
return nil, err
}
err = json.Unmarshal(byteMetada,&metadata)
err = json.Unmarshal(byteMetada, &metadata)
if err != nil {
fmt.Println("Error while Unmarshalling metadata field to the library object")
return nil,err
return nil, err
}
listTargets = append(listTargets, metadata.Name)
}
return listTargets,nil
return listTargets, nil
}
// Admiralty Target allows a cluster to deploy pods to remote cluster
// Admiralty Target allows a cluster to deploy pods to remote cluster
//
// The remote cluster must :
//
@@ -250,20 +248,20 @@ func (k *KubernetesService) GetTargets(ctx context.Context) ([]string,error){
//
// - have declared the same namespace as the one where the pods are created in the local cluster
//
// - have delcared a serviceAccount with sufficient permission to create pods
func (k *KubernetesService) CreateAdmiraltyTarget(context context.Context,executionId string)([]byte,error){
exists, err := k.GetKubeconfigSecret(context,executionId)
// - have delcared a serviceAccount with sufficient permission to create pods
func (k *KubernetesService) CreateAdmiraltyTarget(context context.Context, executionId string) ([]byte, error) {
exists, err := k.GetKubeconfigSecret(context, executionId)
if err != nil {
fmt.Println("Error verifying kube-secret before creating target")
return nil, err
}
if exists == nil {
fmt.Println("Target needs to be binded to a secret in namespace ",executionId)
return nil, nil // Maybe we could create a wrapper for errors and add more info to have
fmt.Println("Target needs to be binded to a secret in namespace ", executionId)
return nil, nil // Maybe we could create a wrapper for errors and add more info to have
}
var targetManifest string
var targetManifest string
var tpl bytes.Buffer
tmpl, err := template.New("target").
Parse("{\"apiVersion\": \"multicluster.admiralty.io/v1alpha1\", \"kind\": \"Target\", \"metadata\": {\"name\": \"target-{{.ExecutionId}}\"}, \"spec\": { \"kubeconfigSecret\" :{\"name\": \"kube-secret-{{.ExecutionId}}\"}} }")
@@ -272,26 +270,25 @@ func (k *KubernetesService) CreateAdmiraltyTarget(context context.Context,execut
return nil, err
}
err = tmpl.Execute(&tpl, map[string]string{"ExecutionId":executionId})
err = tmpl.Execute(&tpl, map[string]string{"ExecutionId": executionId})
targetManifest = tpl.String()
resp, err := postCDRapiKube(
*k.Set,
context,
"/apis/multicluster.admiralty.io/v1alpha1/namespaces/"+ executionId +"/targets",
"/apis/multicluster.admiralty.io/v1alpha1/namespaces/"+executionId+"/targets",
[]byte(targetManifest),
map[string]string{"fieldManager":"kubectl-client-side-apply"},
map[string]string{"fieldValidation":"Strict"},
map[string]string{"fieldManager": "kubectl-client-side-apply"},
map[string]string{"fieldValidation": "Strict"},
)
if err != nil {
fmt.Println("Error trying to create a Source on remote cluster : ", err , " : ", resp)
fmt.Println("Error trying to create a Source on remote cluster : ", err, " : ", resp)
return nil, err
}
return resp, nil
}
// Admiralty Source allows a cluster to receive pods from a remote cluster
//
// The source must be associated to a serviceAccount, which will execute the pods locally.
@@ -300,8 +297,8 @@ func (k *KubernetesService) CreateAdmiraltyTarget(context context.Context,execut
// This method is temporary to implement the use of Admiralty, but must be edited
// to rather contact the oc-datacenter from the remote cluster to create the source
// locally and retrieve the token for the serviceAccount
func (k *KubernetesService) CreateAdmiraltySource(context context.Context,executionId string) ([]byte, error) {
var sourceManifest string
func (k *KubernetesService) CreateAdmiraltySource(context context.Context, executionId string) ([]byte, error) {
var sourceManifest string
var tpl bytes.Buffer
tmpl, err := template.New("source").
Parse("{\"apiVersion\": \"multicluster.admiralty.io/v1alpha1\", \"kind\": \"Source\", \"metadata\": {\"name\": \"source-{{.ExecutionId}}\"}, \"spec\": {\"serviceAccountName\": \"sa-{{.ExecutionId}}\"} }")
@@ -310,21 +307,21 @@ func (k *KubernetesService) CreateAdmiraltySource(context context.Context,execut
return nil, err
}
err = tmpl.Execute(&tpl, map[string]string{"ExecutionId":executionId})
err = tmpl.Execute(&tpl, map[string]string{"ExecutionId": executionId})
sourceManifest = tpl.String()
resp, err := postCDRapiKube(
*k.Set,
context,
"/apis/multicluster.admiralty.io/v1alpha1/namespaces/"+ executionId +"/sources",
"/apis/multicluster.admiralty.io/v1alpha1/namespaces/"+executionId+"/sources",
[]byte(sourceManifest),
map[string]string{"fieldManager":"kubectl-client-side-apply"},
map[string]string{"fieldValidation":"Strict"},
map[string]string{"fieldManager": "kubectl-client-side-apply"},
map[string]string{"fieldValidation": "Strict"},
)
// We can add more info to the log with the content of resp if not nil
if err != nil {
fmt.Println("Error trying to create a Source on remote cluster : ", err , " : ", resp)
fmt.Println("Error trying to create a Source on remote cluster : ", err, " : ", resp)
return nil, err
}
@@ -333,7 +330,7 @@ func (k *KubernetesService) CreateAdmiraltySource(context context.Context,execut
// Create a secret from a kubeconfing. Use it to create the secret binded to an Admiralty
// target, which must contain the serviceAccount's token value
func (k *KubernetesService) CreateKubeconfigSecret(context context.Context,kubeconfig string, executionId string) ([]byte, error) {
func (k *KubernetesService) CreateKubeconfigSecret(context context.Context, kubeconfig string, executionId string) ([]byte, error) {
config, err := base64.StdEncoding.DecodeString(kubeconfig)
// config, err := base64.RawStdEncoding.DecodeString(kubeconfig)
if err != nil {
@@ -345,14 +342,14 @@ func (k *KubernetesService) CreateKubeconfigSecret(context context.Context,kubec
secretManifest := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "kube-secret-" + executionId,
Namespace: executionId,
Namespace: executionId,
},
Data: map[string][]byte{
"config": config,
},
}
exists, err := k.GetKubeconfigSecret(context,executionId)
exists, err := k.GetKubeconfigSecret(context, executionId)
if err != nil {
fmt.Println("Error verifying if kube secret exists in namespace ", executionId)
return nil, err
@@ -366,11 +363,11 @@ func (k *KubernetesService) CreateKubeconfigSecret(context context.Context,kubec
_ = err
}
resp, err := k.Set.CoreV1().
Secrets(executionId).
Create(context,secretManifest,metav1.CreateOptions{})
Secrets(executionId).
Create(context, secretManifest, metav1.CreateOptions{})
if err != nil {
fmt.Println("Error while trying to contact API to get secret kube-secret-"+executionId)
fmt.Println("Error while trying to contact API to get secret kube-secret-" + executionId)
fmt.Println(err)
return nil, err
}
@@ -382,19 +379,19 @@ func (k *KubernetesService) CreateKubeconfigSecret(context context.Context,kubec
return nil, err
}
return data, nil
}
}
func (k *KubernetesService) GetKubeconfigSecret(context context.Context,executionId string) ([]byte, error) {
func (k *KubernetesService) GetKubeconfigSecret(context context.Context, executionId string) ([]byte, error) {
resp, err := k.Set.CoreV1().
Secrets(executionId).
Get(context,"kube-secret-"+executionId,metav1.GetOptions{})
Secrets(executionId).
Get(context, "kube-secret-"+executionId, metav1.GetOptions{})
if err != nil {
if(apierrors.IsNotFound(err)){
if apierrors.IsNotFound(err) {
fmt.Println("kube-secret not found for execution", executionId)
return nil, nil
}
fmt.Println("Error while trying to contact API to get secret kube-secret-"+executionId)
fmt.Println("Error while trying to contact API to get secret kube-secret-" + executionId)
fmt.Println(err)
return nil, err
}
@@ -410,41 +407,41 @@ func (k *KubernetesService) GetKubeconfigSecret(context context.Context,executio
return data, nil
}
func (k *KubernetesService) DeleteKubeConfigSecret(executionID string) ([]byte, error){
func (k *KubernetesService) DeleteKubeConfigSecret(executionID string) ([]byte, error) {
return []byte{}, nil
}
func getCDRapiKube(client kubernetes.Clientset, ctx context.Context, path string) ([]byte,error) {
func getCDRapiKube(client kubernetes.Clientset, ctx context.Context, path string) ([]byte, error) {
resp, err := client.RESTClient().Get().
AbsPath(path).
DoRaw(ctx) // from https://stackoverflow.com/questions/60764908/how-to-access-kubernetes-crd-using-client-go
AbsPath(path).
DoRaw(ctx) // from https://stackoverflow.com/questions/60764908/how-to-access-kubernetes-crd-using-client-go
if err != nil {
fmt.Println("Error from k8s API when getting " + path + " : " , err)
return nil,err
fmt.Println("Error from k8s API when getting "+path+" : ", err)
return nil, err
}
return resp, nil
}
func postCDRapiKube(client kubernetes.Clientset, ctx context.Context, path string, body []byte, params ...map[string]string) ([]byte, error){
func postCDRapiKube(client kubernetes.Clientset, ctx context.Context, path string, body []byte, params ...map[string]string) ([]byte, error) {
req := client.RESTClient().
Post().
AbsPath(path).
Body(body)
Post().
AbsPath(path).
Body(body)
for _, param := range params {
for k,v := range param {
req = req.Param(k,v)
for k, v := range param {
req = req.Param(k, v)
}
}
resp, err := req.DoRaw(ctx)
if err != nil {
fmt.Println("Error from k8s API when posting " + string(body) + " to " + path + " : " , err)
return nil,err
fmt.Println("Error from k8s API when posting "+string(body)+" to "+path+" : ", err)
return nil, err
}
return resp, nil
@@ -453,13 +450,13 @@ func postCDRapiKube(client kubernetes.Clientset, ctx context.Context, path strin
// Returns the Kubernetes' Node object corresponding to the executionID if it exists on this host
//
// The node is created when an admiralty Target (on host) can connect to an admiralty Source (on remote)
func (k *KubernetesService) GetOneNode(context context.Context,executionID string) (*v1.Node, error) {
func (k *KubernetesService) GetOneNode(context context.Context, executionID string) (*v1.Node, error) {
res, err := k.Set.CoreV1().
Nodes().
List(
context,
metav1.ListOptions{},
)
Nodes().
List(
context,
metav1.ListOptions{},
)
if err != nil {
fmt.Println("Error getting the list of nodes from k8s API")
fmt.Println(err)
@@ -467,10 +464,10 @@ func (k *KubernetesService) GetOneNode(context context.Context,executionID strin
}
for _, node := range res.Items {
if isNode := strings.Contains(node.Name,"admiralty-"+executionID+"-target-"+executionID+"-"); isNode {
if isNode := strings.Contains(node.Name, "admiralty-"+executionID+"-target-"+executionID+"-"); isNode {
return &node, nil
}
}
return nil, nil
}
}