github.com/verrazzano/verrazzano@v1.7.1/tools/oam-converter/pkg/app/confdata.go (about)

     1  // Copyright (c) 2023, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package app
     5  
     6  import (
     7  	"encoding/json"
     8  	"errors"
     9  	"fmt"
    10  	consts "github.com/verrazzano/verrazzano/tools/oam-converter/pkg/constants"
    11  	"github.com/verrazzano/verrazzano/tools/oam-converter/pkg/resources"
    12  	"github.com/verrazzano/verrazzano/tools/oam-converter/pkg/traits"
    13  	"github.com/verrazzano/verrazzano/tools/oam-converter/pkg/types"
    14  	workload "github.com/verrazzano/verrazzano/tools/oam-converter/pkg/workloads"
    15  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    16  	"os"
    17  	"path/filepath"
    18  	"sigs.k8s.io/controller-runtime/pkg/client"
    19  	"sigs.k8s.io/controller-runtime/pkg/client/config"
    20  	"sigs.k8s.io/yaml"
    21  	"strings"
    22  )
    23  
    24  func ConfData() error {
    25  
    26  	var inputDirectory string
    27  	var outputDirectory string
    28  
    29  	//Check the length of args
    30  	if len(os.Args) != 3 {
    31  
    32  		return errors.New("not enough args to run tool. Add input directory path and output directory path as args")
    33  
    34  	}
    35  	inputDirectory = os.Args[1]
    36  	outputDirectory = os.Args[2]
    37  
    38  	//used to store app file data
    39  	var appData []map[string]interface{}
    40  
    41  	//used to store comp file data
    42  	var components []map[string]interface{}
    43  
    44  	//used to store non-oam file data
    45  	//	var k8sResources unstructured.Unstructured
    46  
    47  	//iterate through user inputted directory
    48  	files, err := iterateDirectory(inputDirectory)
    49  	if err != nil {
    50  
    51  		return fmt.Errorf("error in iterating over directory %w", err)
    52  	}
    53  
    54  	//Read each file from the input directory
    55  	for _, input := range files {
    56  		data, err := os.ReadFile(input)
    57  		if err != nil {
    58  			return fmt.Errorf("error in reading file %w", err)
    59  		}
    60  
    61  		datastr := string(data)
    62  
    63  		//Split the objects using "---" delimiter
    64  		objects := strings.Split(datastr, "---")
    65  
    66  		//Iterate over each object to segregate into applicationConfiguration kind or Component kind
    67  		for _, obj := range objects {
    68  			var component map[string]interface{}
    69  			err := yaml.Unmarshal([]byte(obj), &component)
    70  			if err != nil {
    71  				return errors.New("error in unmarshalling the components")
    72  			}
    73  			compKind, found, err := unstructured.NestedString(component, "kind")
    74  			if !found || err != nil {
    75  				return errors.New("component kind doesn't exist or not found in the specified type")
    76  			}
    77  			compVersion, found, err := unstructured.NestedString(component, "apiVersion")
    78  			if !found || err != nil {
    79  				return errors.New("component api version doesn't exist or not found in the specified type")
    80  			}
    81  
    82  			//Check the kind of each component and apiVersion
    83  			if compKind == "Component" && compVersion == consts.CompAPIVersion {
    84  				components = append(components, component)
    85  			} else if compKind == "ApplicationConfiguration" && compVersion == consts.CompAPIVersion {
    86  				appData = append(appData, component)
    87  			}
    88  
    89  		}
    90  	}
    91  
    92  	//Extract traits from app file
    93  	conversionComponents, err := traits.ExtractTrait(appData)
    94  
    95  	if err != nil {
    96  		return errors.New("failed extracting traits from app")
    97  	}
    98  	//Extract workloads from app file
    99  
   100  	conversionComponents, err = workload.ExtractWorkload(components, conversionComponents)
   101  
   102  	if err != nil {
   103  		return errors.New("error in extracting workload")
   104  	}
   105  
   106  	cfg, _ := config.GetConfig()
   107  	cli, _ := client.New(cfg, client.Options{})
   108  	//Create child resources
   109  	outputResources, err := resources.CreateResources(cli, conversionComponents)
   110  
   111  	if err != nil {
   112  		return err
   113  	}
   114  	//Write the K8s child resources to the file
   115  	err = writeKubeResources(outputDirectory, outputResources)
   116  	if err != nil {
   117  		return err
   118  
   119  	}
   120  	return nil
   121  }
   122  
   123  // writeKubeResources Write the kube resources to the files in output directory
   124  func writeKubeResources(outputDirectory string, outputResources *types.KubeResources) (err error) {
   125  
   126  	//Write virtual services to files
   127  	if outputResources.VirtualServices != nil {
   128  		for _, virtualService := range outputResources.VirtualServices {
   129  
   130  			fileName := "" + virtualService.Name + ".yaml"
   131  			filePath := filepath.Join(outputDirectory, fileName)
   132  
   133  			f, err := os.Create(filePath)
   134  			if err != nil {
   135  				return err
   136  			}
   137  
   138  			defer f.Close()
   139  
   140  			r, err := json.Marshal(virtualService)
   141  			if err != nil {
   142  				return err
   143  			}
   144  			output, err := yaml.JSONToYAML(r)
   145  			if err != nil {
   146  				return err
   147  			}
   148  
   149  			_, err = f.WriteString(string(output))
   150  			if err != nil {
   151  				return err
   152  			}
   153  
   154  		}
   155  	}
   156  
   157  	//Write down gateway to files
   158  	if outputResources.Gateway != nil {
   159  
   160  		fileName := "gateway.yaml"
   161  		filePath := filepath.Join(outputDirectory, fileName)
   162  
   163  		f, err := os.Create(filePath)
   164  		if err != nil {
   165  			return err
   166  		}
   167  		defer f.Close()
   168  		gatewayYaml, err := yaml.Marshal(outputResources.Gateway)
   169  		if err != nil {
   170  			return fmt.Errorf("failed to marshal YAML: %w", err)
   171  		}
   172  
   173  		_, err = f.WriteString(string(gatewayYaml))
   174  		if err != nil {
   175  			return fmt.Errorf("failed to write YAML to file: %w", err)
   176  		}
   177  
   178  	}
   179  
   180  	//Write down destination rules to files
   181  	if outputResources.DestinationRules != nil {
   182  		for _, destinationRule := range outputResources.DestinationRules {
   183  
   184  			if destinationRule != nil {
   185  				fileName := "" + destinationRule.Name
   186  				filePath := filepath.Join(outputDirectory, fileName)
   187  
   188  				f, err := os.Create(filePath)
   189  				if err != nil {
   190  					return err
   191  				}
   192  
   193  				defer f.Close()
   194  
   195  				r, err := json.Marshal(destinationRule)
   196  				if err != nil {
   197  					return err
   198  				}
   199  				output, err := yaml.JSONToYAML(r)
   200  				if err != nil {
   201  					return err
   202  				}
   203  				_, err2 := f.WriteString(string(output))
   204  				if err2 != nil {
   205  					return err2
   206  				}
   207  			}
   208  		}
   209  	}
   210  
   211  	//Write down Authorization Policies to files
   212  	if outputResources.AuthPolicies != nil {
   213  		for _, authPolicy := range outputResources.AuthPolicies {
   214  
   215  			if authPolicy != nil {
   216  				fileName := "authzpolicy.yaml"
   217  				filePath := filepath.Join(outputDirectory, fileName)
   218  
   219  				f, err := os.Create(filePath)
   220  				if err != nil {
   221  					return err
   222  				}
   223  
   224  				defer f.Close()
   225  				r, err := json.Marshal(authPolicy)
   226  				if err != nil {
   227  					return err
   228  				}
   229  				output, err := yaml.JSONToYAML(r)
   230  				if err != nil {
   231  					return err
   232  				}
   233  
   234  				_, err2 := f.WriteString(string(output))
   235  				if err2 != nil {
   236  					return err2
   237  				}
   238  			}
   239  		}
   240  	}
   241  
   242  	//Write down Service Monitors to files
   243  	if outputResources.ServiceMonitors != nil {
   244  		var output string
   245  		fileName := "output.yaml"
   246  		filePath := filepath.Join(outputDirectory, fileName)
   247  		f, err := os.Create(filePath)
   248  		if err != nil {
   249  			return err
   250  		}
   251  
   252  		defer f.Close()
   253  
   254  		for _, servicemonitor := range outputResources.ServiceMonitors {
   255  			r, err := json.Marshal(servicemonitor)
   256  			if err != nil {
   257  				return err
   258  
   259  			}
   260  			out, err := yaml.JSONToYAML(r)
   261  			if err != nil {
   262  				return err
   263  			}
   264  			output = output + "---\n" + string(out)
   265  		}
   266  
   267  		_, err2 := f.WriteString(string(output))
   268  		if err2 != nil {
   269  			return err2
   270  		}
   271  
   272  	}
   273  	return nil
   274  
   275  }
   276  
   277  // iterateDirectory Iterate over input directory
   278  func iterateDirectory(path string) ([]string, error) {
   279  	var files []string
   280  
   281  	filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
   282  		if err != nil {
   283  			return err
   284  		}
   285  		if strings.Contains(info.Name(), "yaml") || strings.Contains(info.Name(), "yml") {
   286  			files = append(files, path)
   287  		}
   288  		return nil
   289  	})
   290  	return files, nil
   291  }