//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 main import ( "bufio" "encoding/base64" "flag" "io/ioutil" "os" "path/filepath" "strings" "text/template" "k8s.io/apimachinery/pkg/runtime" "k8s.io/klog" cdicluster "kubevirt.io/containerized-data-importer/pkg/operator/resources/cluster" "kubevirt.io/containerized-data-importer/pkg/operator/resources/namespaced" cdinamespaced "kubevirt.io/containerized-data-importer/pkg/operator/resources/namespaced" cdioperator "kubevirt.io/containerized-data-importer/pkg/operator/resources/operator" ) const ( initialCsvVersion string = "0.0.0" ) type templateData struct { DockerRepo string DockerTag string CsvVersion string ReplacesCsvVersion string QuayNamespace string QuayRepository string OperatorRules string OperatorDeploymentSpec string CDILogo string DeployClusterResources string OperatorImage string ControllerImage string ImporterImage string ClonerImage string APIServerImage string UploadProxyImage string UploadServerImage string Verbosity string PullPolicy string Namespace string GeneratedManifests map[string]string } var ( dockerRepo = flag.String("docker-repo", "", "") dockertag = flag.String("docker-tag", "", "") csvVersion = flag.String("csv-version", "", "") cdiLogoPath = flag.String("cdi-logo-path", "", "") genManifestsPath = flag.String("generated-manifests-path", "", "") quayNamespace = flag.String("quay-namespace", "", "") quayRepository = flag.String("quay-repository", "", "") deployClusterResources = flag.String("deploy-cluster-resources", "", "") operatorImage = flag.String("operator-image", "", "") controllerImage = flag.String("controller-image", "", "") importerImage = flag.String("importer-image", "", "") clonerImage = flag.String("cloner-image", "", "") apiServerImage = flag.String("apiserver-image", "", "") uploadProxyImage = flag.String("uploadproxy-image", "", "") uploadServerImage = flag.String("uploadserver-image", "", "") verbosity = flag.String("verbosity", "1", "") pullPolicy = flag.String("pull-policy", "", "") namespace = flag.String("namespace", "", "") ) func main() { templFile := flag.String("template", "", "") codeGroup := flag.String("code-group", "everything", "") flag.Parse() klogFlags := flag.NewFlagSet("klog", flag.ExitOnError) klog.InitFlags(klogFlags) flag.CommandLine.VisitAll(func(f1 *flag.Flag) { f2 := klogFlags.Lookup(f1.Name) if f2 != nil { value := f1.Value.String() f2.Value.Set(value) } }) if *templFile != "" { generateFromFile(*templFile) return } generateFromCode(*codeGroup) } func getOperatorRules() string { rules := *cdioperator.GetOperatorClusterRules() writer := strings.Builder{} for _, rule := range rules { err := MarshallObject(rule, &writer) if err != nil { panic(err) } } return fixResourceString(writer.String(), 14) } func getOperatorDeploymentSpec() string { args := &cdioperator.FactoryArgs{ Verbosity: *verbosity, DockerRepo: *dockerRepo, DockerTag: *dockertag, DeployClusterResources: *deployClusterResources, OperatorImage: *operatorImage, ControllerImage: *controllerImage, ImporterImage: *importerImage, ClonerImage: *clonerImage, APIServerImage: *apiServerImage, UploadProxyImage: *uploadProxyImage, UploadServerImage: *uploadServerImage, PullPolicy: *pullPolicy, Namespace: *namespace, } spec := cdioperator.GetOperatorDeploymentSpec(args) writer := strings.Builder{} err := MarshallObject(spec, &writer) if err != nil { panic(err) } return fixResourceString(writer.String(), 14) } func fixResourceString(in string, indention int) string { out := strings.Builder{} scanner := bufio.NewScanner(strings.NewReader(in)) for scanner.Scan() { line := scanner.Text() // remove separator lines if !strings.HasPrefix(line, "---") { // indent so that it fits into the manifest // spaces is is indention - 2, because we want to have 2 spaces less for being able to start an array spaces := strings.Repeat(" ", indention-2) if strings.HasPrefix(line, "apiGroups") { // spaces + array start out.WriteString(spaces + "- " + line + "\n") } else { // 2 more spaces out.WriteString(spaces + " " + line + "\n") } } } return out.String() } func generateFromFile(templFile string) { data := &templateData{ Verbosity: *verbosity, DockerRepo: *dockerRepo, DockerTag: *dockertag, CsvVersion: *csvVersion, DeployClusterResources: *deployClusterResources, OperatorImage: *operatorImage, ControllerImage: *controllerImage, ImporterImage: *importerImage, ClonerImage: *clonerImage, APIServerImage: *apiServerImage, UploadProxyImage: *uploadProxyImage, UploadServerImage: *uploadServerImage, PullPolicy: *pullPolicy, Namespace: *namespace, } file, err := os.OpenFile(templFile, os.O_RDONLY, 0) if err != nil { klog.Fatalf("Failed to open file %s: %v\n", templFile, err) } defer file.Close() if strings.Contains(*csvVersion, initialCsvVersion) { data.ReplacesCsvVersion = "" } else { klog.Fatalf("Need to implement CSV upgrade to set ReplacesVersion in CSV when CSVVersion is greater than %s\n", initialCsvVersion) } data.QuayRepository = *quayRepository data.QuayNamespace = *quayNamespace data.OperatorRules = getOperatorRules() data.OperatorDeploymentSpec = getOperatorDeploymentSpec() data.CDILogo = getCdiLogo(*cdiLogoPath) // Read generated manifests in order to populate templated manifest genDir := *genManifestsPath data.GeneratedManifests = make(map[string]string) manifests, err := ioutil.ReadDir(genDir) if err != nil { klog.Fatalf("Failed to read directory %s: %v\n", templFile, err) } for _, manifest := range manifests { if manifest.IsDir() { continue } b, err := ioutil.ReadFile(filepath.Join(genDir, manifest.Name())) if err != nil { klog.Fatalf("Failed to read file %s: %v\n", templFile, err) } data.GeneratedManifests[manifest.Name()] = string(b) } tmpl := template.Must(template.ParseFiles(templFile)) err = tmpl.Execute(os.Stdout, data) if err != nil { klog.Fatalf("Error executing template: %v\n", err) } } func getCdiLogo(path string) string { file, err := os.Open(path) if err != nil { klog.Fatalf("Error retrieving cdi logo file: %v\n", err) } // Read entire file into byte slice. reader := bufio.NewReader(file) content, err := ioutil.ReadAll(reader) if err != nil { klog.Fatalf("Error reading cdi logo file: %v\n", err) } // Encode as base64. encoded := base64.StdEncoding.EncodeToString(content) return encoded } const ( //ClusterResource - cluster resources ClusterResource string = "cluster" //OperatorResource - operator resources OperatorResource string = "operator" //NamespaceResource - namespace resources NamespaceResource string = "namespaces" ) type resourceGet func(string) ([]runtime.Object, error) type resourcetype func(string) bool type resourceTuple struct { resourcetype resourcetype resourceGet resourceGet } var resourcesTable = map[string]resourceTuple{ ClusterResource: {cdicluster.IsFactoryResource, getClusterResources}, NamespaceResource: {namespaced.IsFactoryResource, getNamespacedResources}, OperatorResource: {cdioperator.IsFactoryResource, getOperatorClusterResources}, } func generateFromCode(codeGroup string) { var resources []runtime.Object for r, dispatch := range resourcesTable { if dispatch.resourcetype(codeGroup) { crs, err := dispatch.resourceGet(codeGroup) if err != nil { klog.Fatalf("Error getting %s resources: %v\n", r, err) } resources = append(resources, crs...) } //of codeGroup matches resource then get it } //iterate through all resources for _, resource := range resources { err := MarshallObject(resource, os.Stdout) if err != nil { klog.Fatalf("Error marshalling resource: %v\n", err) } } } const ( //ClusterResourcesCodeGroupEverything - generate all cluster resources ClusterResourcesCodeGroupEverything string = "cluster-everything" //NamespaceResourcesCodeGroupEverything - generate all namespace resources NamespaceResourcesCodeGroupEverything string = "namespace-everything" //ClusterResourcesCodeOperatorGroupEverything - generate all operator resources ClusterResourcesCodeOperatorGroupEverything string = "operator-everything" ) func getOperatorClusterResources(codeGroup string) ([]runtime.Object, error) { args := &cdioperator.FactoryArgs{ Verbosity: *verbosity, DockerRepo: *dockerRepo, DockerTag: *dockertag, DeployClusterResources: *deployClusterResources, OperatorImage: *operatorImage, ControllerImage: *controllerImage, ImporterImage: *importerImage, ClonerImage: *clonerImage, APIServerImage: *apiServerImage, UploadProxyImage: *uploadProxyImage, UploadServerImage: *uploadServerImage, PullPolicy: *pullPolicy, Namespace: *namespace, } if codeGroup == ClusterResourcesCodeOperatorGroupEverything { return cdioperator.CreateAllOperatorResources(args) } return cdioperator.CreateOperatorResourceGroup(codeGroup, args) } func getClusterResources(codeGroup string) ([]runtime.Object, error) { args := &cdicluster.FactoryArgs{ Verbosity: *verbosity, DockerRepo: *dockerRepo, DockerTag: *dockertag, DeployClusterResources: *deployClusterResources, ControllerImage: *controllerImage, ImporterImage: *importerImage, ClonerImage: *clonerImage, APIServerImage: *apiServerImage, UploadProxyImage: *uploadProxyImage, UploadServerImage: *uploadServerImage, PullPolicy: *pullPolicy, Namespace: *namespace, } if codeGroup == ClusterResourcesCodeGroupEverything { return cdicluster.CreateAllResources(args) } return cdicluster.CreateResourceGroup(codeGroup, args) } func getNamespacedResources(codeGroup string) ([]runtime.Object, error) { args := &cdinamespaced.FactoryArgs{ Verbosity: *verbosity, DockerRepo: *dockerRepo, DockerTag: *dockertag, ControllerImage: *controllerImage, ImporterImage: *importerImage, ClonerImage: *clonerImage, APIServerImage: *apiServerImage, UploadProxyImage: *uploadProxyImage, UploadServerImage: *uploadServerImage, PullPolicy: *pullPolicy, Namespace: *namespace, } if codeGroup == NamespaceResourcesCodeGroupEverything { return cdinamespaced.CreateAllResources(args) } return cdinamespaced.CreateResourceGroup(codeGroup, args) }