mirror of
https://github.com/kubevirt/containerized-data-importer.git
synced 2025-06-03 06:30:22 +00:00
407 lines
13 KiB
Go
407 lines
13 KiB
Go
//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"
|
|
"kubevirt.io/containerized-data-importer/tools/marketplace/helper"
|
|
"kubevirt.io/containerized-data-importer/tools/util"
|
|
)
|
|
|
|
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", "", "")
|
|
replacesCsvVersion = flag.String("replaces-csv-version", "", "")
|
|
cdiLogoPath = flag.String("cdi-logo-path", "", "")
|
|
genManifestsPath = flag.String("generated-manifests-path", "", "")
|
|
bundleOut = flag.String("olm-bundle-dir", "", "")
|
|
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 != "" {
|
|
if *replacesCsvVersion == "" {
|
|
var err error
|
|
*replacesCsvVersion, err = evalOlmCsvUpdateVersion(*templFile, *csvVersion, *bundleOut, *quayNamespace, *quayRepository)
|
|
if err != nil {
|
|
klog.Fatalf("Failed to evaluate CSV Replaces Version! %s, %v", *csvVersion, err)
|
|
}
|
|
}
|
|
generateFromFile(*templFile)
|
|
return
|
|
}
|
|
|
|
generateFromCode(*codeGroup)
|
|
}
|
|
|
|
func getOperatorRules() string {
|
|
rules := *cdioperator.GetOperatorClusterRules()
|
|
|
|
writer := strings.Builder{}
|
|
for _, rule := range rules {
|
|
err := util.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,
|
|
|
|
CsvVersion: *csvVersion,
|
|
ReplacesCsvVersion: *replacesCsvVersion,
|
|
CDILogo: getCdiLogo(*cdiLogoPath),
|
|
}
|
|
|
|
spec := cdioperator.GetOperatorDeploymentSpec(args)
|
|
|
|
writer := strings.Builder{}
|
|
|
|
err := util.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 evalOlmCsvUpdateVersion(inFile, csvVersion, bundleOutDir, quayNamespace, quayRepository string) (string, error) {
|
|
replacesCsvVersion := ""
|
|
if strings.Contains(inFile, ".csv.yaml") && bundleOutDir != "" {
|
|
bundleHelper, err := helper.NewBundleHelper(quayRepository, quayNamespace)
|
|
|
|
if err != nil {
|
|
klog.Fatalf("Failed to access quay namespace %s, repo %s, %v\n", quayNamespace, quayRepository, err)
|
|
}
|
|
if !bundleHelper.VerifyNotPublishedCSVVersion(csvVersion) {
|
|
klog.Fatalf("CSV version %s is already published!", csvVersion)
|
|
}
|
|
latestVersion := bundleHelper.GetLatestPublishedCSVVersion()
|
|
if latestVersion != "" {
|
|
// prevent generating the same version again
|
|
if strings.HasSuffix(latestVersion, csvVersion) {
|
|
klog.Fatalf("CSV version %s is already published!", csvVersion)
|
|
}
|
|
replacesCsvVersion = latestVersion
|
|
// also copy old manifests to out dir
|
|
if *bundleOut != "" {
|
|
bundleHelper.AddOldManifests(bundleOutDir, csvVersion)
|
|
}
|
|
}
|
|
}
|
|
return replacesCsvVersion, nil
|
|
}
|
|
|
|
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()
|
|
|
|
data.ReplacesCsvVersion = *replacesCsvVersion
|
|
data.QuayRepository = *quayRepository
|
|
data.QuayNamespace = *quayNamespace
|
|
data.OperatorRules = getOperatorRules()
|
|
data.OperatorDeploymentSpec = getOperatorDeploymentSpec()
|
|
data.CDILogo = getCdiLogo(*cdiLogoPath)
|
|
|
|
// Read generated manifests and 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", genDir, 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: %s, %v\n", path, 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 := util.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,
|
|
|
|
CsvVersion: *csvVersion,
|
|
ReplacesCsvVersion: *replacesCsvVersion,
|
|
CDILogo: getCdiLogo(*cdiLogoPath),
|
|
}
|
|
|
|
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)
|
|
}
|