+
+//Function to create configmap
+func createConfigMap(data, labels map[string]string, namespace string, clientset kubernetes.Interface) error{
+
+ configmapClient := clientset.CoreV1().ConfigMaps(namespace)
+
+ configmap := &corev1.ConfigMap{
+
+ ObjectMeta: metav1.ObjectMeta{
+ Name: labels["cluster"] + "-configmap",
+ Labels: labels,
+ },
+ Data: data,
+ }
+
+
+ _, err := configmapClient.Create(configmap)
+ if err != nil {
+ return err
+
+ }
+ return nil
+
+}
+
+//Function to get configmap Data
+func getConfigMapData(namespace, clusterName string, clientset kubernetes.Interface) (map[string]string, error) {
+
+ configmapClient := clientset.CoreV1().ConfigMaps(namespace)
+ configmapName := clusterName + "-configmap"
+ clusterConfigmap, err := configmapClient.Get(configmapName, metav1.GetOptions{})
+ if err != nil {
+ return nil, err
+ }
+
+ configmapData := clusterConfigmap.Data
+ return configmapData, nil
+}
+
+//Function to create job for KUD installation
+func createKUDinstallerJob(clusterName, namespace string, labels map[string]string, kudPlugins []string, clientset kubernetes.Interface) error{
+
+ var backOffLimit int32 = 0
+ var privi bool = true
+
+ installerString := " ./installer --cluster " + clusterName
+
+ // Check if any plugin was specified
+ if len(kudPlugins) > 0 {
+ plugins := " --plugins"
+
+ for _, plug := range kudPlugins {
+ plugins += " " + plug
+ }
+
+ installerString += plugins
+ }
+
+
+ jobClient := clientset.BatchV1().Jobs("default")
+
+ job := &batchv1.Job{
+
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "kud-" + clusterName,
+ Labels: labels,
+ },
+ Spec: batchv1.JobSpec{
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{
+ Labels: labels,
+ },
+
+
+ Spec: corev1.PodSpec{
+ HostNetwork: true,
+ Containers: []corev1.Container{{
+ Name: "kud",
+ Image: "github.com/onap/multicloud-k8s:latest",
+ ImagePullPolicy: "IfNotPresent",
+ VolumeMounts: []corev1.VolumeMount{{
+ Name: "multi-cluster",
+ MountPath: "/opt/kud/multi-cluster",
+ },
+ {
+ Name: "secret-volume",
+ MountPath: "/.ssh",
+ },
+
+ },
+ Command: []string{"/bin/sh","-c"},
+ Args: []string{"cp -r /.ssh /root/; chmod -R 600 /root/.ssh;" + installerString},
+ SecurityContext: &corev1.SecurityContext{
+ Privileged : &privi,
+
+ },
+ },
+ },
+ Volumes: []corev1.Volume{{
+ Name: "multi-cluster",
+ VolumeSource: corev1.VolumeSource{
+ HostPath: &corev1.HostPathVolumeSource{
+ Path : "/opt/kud/multi-cluster",
+ }}},
+ {
+ Name: "secret-volume",
+ VolumeSource: corev1.VolumeSource{
+ Secret: &corev1.SecretVolumeSource{
+ SecretName: "ssh-key-secret",
+ },
+
+ }}},
+ RestartPolicy: "Never",
+ },
+
+ },
+ BackoffLimit : &backOffLimit,
+ },
+
+ }
+ _, err := jobClient.Create(job)
+ if err != nil {
+ fmt.Printf("ERROR occured while creating job to install KUD\n ERROR:%v", err)
+ return err
+ }
+ return nil
+
+}
+
+//Function to Check if job succeeded
+func checkJob(clusterName, namespace string, data, labels map[string]string, clientset kubernetes.Interface) {
+
+ fmt.Printf("\nChecking job status for cluster %s\n", clusterName)
+ jobName := "kud-" + clusterName
+ jobClient := clientset.BatchV1().Jobs(namespace)
+
+ for {
+ time.Sleep(2 * time.Second)
+
+ job, err := jobClient.Get(jobName, metav1.GetOptions{})
+ if err != nil {
+ fmt.Printf("ERROR: %v occured while retrieving job: %s", err, jobName)
+ return
+ }
+ jobSucceeded := job.Status.Succeeded
+ jobFailed := job.Status.Failed
+
+ if jobSucceeded == 1 {
+ fmt.Printf("\n Job succeeded, KUD successfully installed in Cluster %s\n", clusterName)
+
+ //KUD was installed successfully create configmap to store IP address info for the cluster
+ err = createConfigMap(data, labels, namespace, clientset)
+ if err != nil {
+ fmt.Printf("Error occured while creating Ip address configmap for cluster %v\n ERROR: %v", clusterName, err)
+ return
+ }
+ return
+ }
+
+ if jobFailed == 1 {
+ fmt.Printf("\n Job Failed, KUD not installed in Cluster %s, check pod logs\n", clusterName)
+ return
+ }
+
+ }
+ return
+
+}
+
+//Function to get software list from software CR
+func getSoftwareList(softwareCR *bpav1alpha1.Software) (string, []interface{}, []interface{}) {
+
+ CRclusterName := softwareCR.GetLabels()["cluster"]
+
+ masterSofwareList := softwareCR.Spec.MasterSoftware
+ workerSoftwareList := softwareCR.Spec.WorkerSoftware
+
+ return CRclusterName, masterSofwareList, workerSoftwareList
+}
+
+//Function to install software in clusterHosts
+func softwareInstaller(ipAddress, sshPrivateKey string, softwareList []interface{}) error {
+
+ var installString string
+ for _, software := range softwareList {
+
+ switch t := software.(type){
+ case string:
+ installString += software.(string) + " "
+ case interface{}:
+ softwareMap, errBool := software.(map[string]interface{})
+ if !errBool {
+ fmt.Printf("Error occured, cannot install software %v\n", software)
+ }
+ for softwareName, versionMap := range softwareMap {
+
+ versionMAP, _ := versionMap.(map[string]interface{})
+ version := versionMAP["version"].(string)
+ installString += softwareName + "=" + version + " "
+ }
+ default:
+ fmt.Printf("invalid format %v\n", t)
+ }
+
+ }
+
+ err := sshInstaller(installString, sshPrivateKey, ipAddress)
+ if err != nil {
+ return err
+ }
+ return nil
+
+}
+
+//Function to Run Installation commands via ssh
+func sshInstaller(softwareString, sshPrivateKey, ipAddress string) error {
+
+ buffer, err := ioutil.ReadFile(sshPrivateKey)
+ if err != nil {
+ return err
+ }
+
+ key, err := ssh.ParsePrivateKey(buffer)
+ if err != nil {
+ return err
+ }
+
+ sshConfig := &ssh.ClientConfig{
+ User: "root",
+ Auth: []ssh.AuthMethod{
+ ssh.PublicKeys(key),
+ },
+
+ HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+ }
+
+ client, err := ssh.Dial("tcp", ipAddress + ":22", sshConfig)
+ if err != nil {
+ return err
+ }
+
+ session, err := client.NewSession()
+ if err != nil {
+ return err
+ }
+
+ defer session.Close()
+ defer client.Close()
+
+ cmd := "sudo apt-get update && apt-get install " + softwareString + "-y"
+ err = session.Start(cmd)
+
+ if err != nil {
+ return err
+ }
+
+ return nil
+
+}
+
+func listVirtletVMs(clientset kubernetes.Interface) ([]VirtletVM, error) {
+
+ var vmPodList []VirtletVM
+
+ pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{})
+ if err != nil {
+ fmt.Printf("Could not get pod info, Error: %v\n", err)
+ return []VirtletVM{}, err
+ }
+
+ for _, pod := range pods.Items {
+ var podAnnotation map[string]interface{}
+ var podStatus corev1.PodStatus
+ var podDefaultNetStatus []NetworksStatus
+
+ annotation, err := json.Marshal(pod.ObjectMeta.GetAnnotations())
+ if err != nil {
+ fmt.Printf("Could not get pod annotations, Error: %v\n", err)
+ return []VirtletVM{}, err
+ }
+
+ json.Unmarshal([]byte(annotation), &podAnnotation)
+ if podAnnotation != nil && podAnnotation["kubernetes.io/target-runtime"] != nil {
+ runtime := podAnnotation["kubernetes.io/target-runtime"].(string)
+
+ podStatusJson, _ := json.Marshal(pod.Status)
+ json.Unmarshal([]byte(podStatusJson), &podStatus)
+
+ if runtime == "virtlet.cloud" && podStatus.Phase == "Running" && podAnnotation["v1.multus-cni.io/default-network"] != nil {
+ ns := podAnnotation["v1.multus-cni.io/default-network"].(string)
+ json.Unmarshal([]byte(ns), &podDefaultNetStatus)
+
+ vmPodList = append(vmPodList, VirtletVM{podStatus.PodIP, podDefaultNetStatus[0].Mac})
+ }
+ }
+ }
+
+ return vmPodList, nil
+}
+
+func getVMIPaddress(vmList []VirtletVM, macAddress string) (string, error) {
+
+ for i := 0; i < len(vmList); i++ {
+ if vmList[i].MACaddress == macAddress {
+ return vmList[i].IPaddress, nil
+ }
+ }
+ return "", nil
+}