Skip to content

Commit

Permalink
Add Ambient Mesh Support
Browse files Browse the repository at this point in the history
  • Loading branch information
Romero027 committed May 4, 2024
1 parent 724270d commit 4319fd7
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 4 deletions.
131 changes: 131 additions & 0 deletions internal/controller/ambient_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
Copyright 2024.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package controller

import (
"bufio"
"context"
"flag"
"fmt"
"os"
"path/filepath"
"regexp"

corev1 "k8s.io/api/core/v1"
// appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)

func find_service_account(file_name string) string {
file, err := os.Open(file_name)
if err != nil {
fmt.Println("Error opening file:", err)
return ""
}
defer file.Close()

// Create a regular expression to match the service account
re := regexp.MustCompile(`--service-account\s+(\S+)`)

// Create a scanner to read the file line by line
scanner := bufio.NewScanner(file)

// Iterate through each line of the file
for scanner.Scan() {
line := scanner.Text()
// Check if the line contains the service account
match := re.FindStringSubmatch(line)
if len(match) > 1 {
// Extract the service account from the matched line
serviceAccount := match[1]
return serviceAccount
}
}

// Check for scanner errors
if err := scanner.Err(); err != nil {
return ""
}

return ""
}

func attach_volume_to_waypoint(service_name, service_account string) {
// Set up kubeconfig path
var k8sconfig *string
if home := homedir.HomeDir(); home != "" {
k8sconfig = flag.String("k8sconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
} else {
k8sconfig = flag.String("k8sconfig", "", "absolute path to the k8sconfig file")
}
flag.Parse()

// Use the current context in kubeconfig
config, err := clientcmd.BuildConfigFromFlags("", *k8sconfig)
if err != nil {
panic(err.Error())
}

// Create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}

// Set deployment details
namespace := "default"
deploymentName := service_account + "-istio-waypoint"
pvcName := service_name + "-pvc"
mountPath := "/data"

// Get the specified deployment
deployment, err := clientset.AppsV1().Deployments(namespace).Get(context.TODO(), deploymentName, metav1.GetOptions{})
if err != nil {
panic(err.Error())
}

// Define the volume and volume mount
volume := corev1.Volume{
Name: service_name + "-storage",
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: pvcName,
},
},
}
volumeMount := corev1.VolumeMount{
Name: service_name + "-storage",
MountPath: mountPath,
}

// Attach the volume to the deployment spec
deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes, volume)
for i := range deployment.Spec.Template.Spec.Containers {
deployment.Spec.Template.Spec.Containers[i].VolumeMounts = append(deployment.Spec.Template.Spec.Containers[i].VolumeMounts, volumeMount)
}

// Update the deployment
_, err = clientset.AppsV1().Deployments(namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
if err != nil {
panic(err.Error())
}

// fmt.Printf("Deployment '%s' in namespace '%s' updated successfully.\n", deploymentName, namespace)
}
25 changes: 24 additions & 1 deletion internal/controller/appnetconfig_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ func (r *AppNetConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request
}

backend := config.Spec.Backend

// temporary fix for sidecar backend
if backend == "sidecar" {
backend = "envoy"
}

client_service := config.Spec.ClientService
server_service := config.Spec.ServerService
client_elements := config.Spec.ClientChain
Expand All @@ -86,7 +92,7 @@ func (r *AppNetConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request
"Backend:", backend, "Client Service", client_service, "Server Service", server_service, "client-side Elements", client_elements,
"server-side Elements", server_elements, "unconstraint Elements", any_elements, "pair Elements", pair_elements)

ConvertToAppNetSpec(app_name, app_manifest_file, client_service, server_service, method, proto, "config.yaml", client_elements, server_elements,
ConvertToAppNetSpec(app_name, backend, app_manifest_file, client_service, server_service, method, proto, "config.yaml", client_elements, server_elements,
any_elements, pair_elements)

compilerDir := filepath.Join(os.Getenv("APPNET_DIR"), "compiler/compiler")
Expand All @@ -111,6 +117,23 @@ func (r *AppNetConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request
return ctrl.Result{}, client.IgnoreNotFound(err)
}

// Deploy waypoint proxies
if backend == "ambient" {
waypoint_cmd := exec.Command("bash", strings.ReplaceAll(filepath.Join(compilerDir, "graph/generated/APP-deploy/waypoint_create.sh"), "APP", app_name))
waypoint_output, waypoint_err := waypoint_cmd.CombinedOutput()

// Check if there was an error running the command
if waypoint_err != nil {
l.Info("Reconciling AppNetConfig", "Error running istioctl waypoint: %s\nOutput:\n%s\n", waypoint_err, string(waypoint_output))
return ctrl.Result{}, client.IgnoreNotFound(err)
}

// Attach volume to waypoint
service_account := find_service_account(strings.ReplaceAll(filepath.Join(compilerDir, "graph/generated/APP-deploy/waypoint_create.sh"), "APP", app_name))
l.Info("Reconciling AppNetConfig", server_service, service_account)
attach_volume_to_waypoint(server_service, service_account)
}

l.Info("All elemenets deployed - Reconciliation finished!")

return ctrl.Result{}, nil
Expand Down
15 changes: 12 additions & 3 deletions internal/controller/spec_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type PairElementItem struct {
Proto string `yaml:"proto"`
}

func ConvertToAppNetSpec(appName, appManifestFile, clientService, serverService, method, proto, fileName string, clientChain, serverChain, anyChain, pairChain []apiv1.ChainElement) error {
func ConvertToAppNetSpec(appName, backend, appManifestFile, clientService, serverService, method, proto, fileName string, clientChain, serverChain, anyChain, pairChain []apiv1.ChainElement) error {
clientServerTag := fmt.Sprintf("%s->%s", clientService, serverService)

appManifest := AppManifest{
Expand All @@ -45,12 +45,17 @@ func ConvertToAppNetSpec(appName, appManifestFile, clientService, serverService,
Link: make(map[string][]PairElementItem),
}

position := ""
if len(clientChain) > 0 {
// All ambinet elements are considered to be on the server-side
if backend == "ambient" {
position = "S"
}
for _, element := range clientChain {
appManifest.Edge[clientServerTag] = append(appManifest.Edge[clientServerTag], EdgeElementItem{
Method: method,
Name: element.Name,
Position: "C",
Position: position,
Proto: proto,
Path: element.File,
})
Expand All @@ -70,11 +75,15 @@ func ConvertToAppNetSpec(appName, appManifestFile, clientService, serverService,
}

if len(anyChain) > 0 {
// All ambinet elements are considered to be on the server-side
if backend == "ambient" {
position = "S"
}
for _, element := range anyChain {
appManifest.Edge[clientServerTag] = append(appManifest.Edge[clientServerTag], EdgeElementItem{
Method: method,
Name: element.Name,
Position: "C/S",
Position: position,
Proto: proto,
Path: element.File,
})
Expand Down

0 comments on commit 4319fd7

Please sign in to comment.