func()

in gke-deploy/deployer/deployer.go [45:305]


func (d *Deployer) Prepare(ctx context.Context, im name.Reference, appName, appVersion, config, suggestedOutput, expandedOutput, namespace string, labels, annotations map[string]string, exposePort int, recursive, createApplicationCR bool, applicationLinks []applicationsv1beta1.Link) error {
	fmt.Printf("Preparing deployment.\n")

	var objs resource.Objects
	ss := &gcs.GCS{
		GcsService: d.Clients.GCS,
	}
	if config != "" {

		if strings.HasPrefix(config, "gs://") {
			tmpDir, err := d.Clients.OS.TempDir(ctx, "", k8sConfigStagingDir)
			if err != nil {
				return fmt.Errorf("failed to create tmp directory: %v", err)
			}
			defer d.Clients.OS.RemoveAll(ctx, tmpDir)
			err = ss.Download(ctx, config, tmpDir, recursive)
			if err != nil {
				return fmt.Errorf("failed to download configuration files from GCS %q: %v", config, err)
			}
			config = tmpDir
		}

		parsed, err := resource.ParseConfigs(ctx, config, d.Clients.OS, recursive)
		if err != nil {
			return fmt.Errorf("failed to parse configuration files %q: %v", config, err)
		}
		if len(parsed) == 0 {
			return fmt.Errorf("no objects found")
		}
		objs = parsed
		fmt.Printf("Configuration files to be used: %v\n", objs)
	} else {
		objs = resource.Objects{}
		fmt.Println("Starting with no configuration files")
	}

	if im != nil {
		// e.g., Resolve "gcr.io/my-project/my-app:1.0.0" to name suffix "my-app".
		imageNameSplit := strings.Split(image.Name(im), "/")
		imageNameSuffix := imageNameSplit[len(imageNameSplit)-1]
		imageName := image.Name(im)

		if config == "" {
			fmt.Printf("Creating suggested Deployment configuration file %q\n", imageNameSuffix)
			dObj, err := resource.CreateDeploymentObject(ctx, imageNameSuffix, imageNameSuffix, imageName)
			if err != nil {
				return fmt.Errorf("failed to create Deployment object: %v", err)
			}

			objs = append(objs, dObj)

			hpaName := fmt.Sprintf("%s-hpa", imageNameSuffix)
			fmt.Printf("Creating suggested HorizontalPodAutoscaler configuration file %q\n", hpaName)
			hpaObj, err := resource.CreateHorizontalPodAutoscalerObject(ctx, hpaName, imageNameSuffix)
			if err != nil {
				return fmt.Errorf("failed to create HorizontalPodAutoscaler object: %v", err)
			}
			objs = append(objs, hpaObj)
		}

		// Remove tag/digest from image references.
		if err := resource.UpdateMatchingContainerImage(ctx, objs, imageName, imageName); err != nil {
			return fmt.Errorf("failed to update container of objects: %v", err)
		}
	}

	if appName != "" {
		if exposePort > 0 {
			service := fmt.Sprintf("%s-service", appName)
			ok, err := resource.HasObject(ctx, objs, "Service", service)
			if err != nil {
				return fmt.Errorf("failed to check if Service %q exists: %v", service, err)
			}
			if !ok {
				fmt.Printf("Creating suggested Service configuration file %q\n", service)
				svcObj, err := resource.CreateServiceObject(ctx, service, appNameLabelKey, appName, exposePort)
				if err != nil {
					return fmt.Errorf("failed to create Service object: %v", err)
				}
				objs = append(objs, svcObj)
			} else {
				fmt.Fprintf(os.Stderr, "\nWARNING: Service %q already exists in provided configuration files. Not generating new Service.\n\n", service)
			}
		}

		if createApplicationCR {
			ok, err := resource.HasObject(ctx, objs, "Application", appName)
			if err != nil {
				return fmt.Errorf("failed to check if Application %q exists: %v", appName, err)
			}
			if !ok {
				fmt.Printf("Creating suggested Application configuration file %q\n", appName)
				appObj, err := resource.CreateApplicationObject(appName, appNameLabelKey, appName, appName, appVersion, objs)
				if err != nil {
					return fmt.Errorf("failed to create Application object: %v", err)
				}
				objs = append(objs, appObj)
			} else {
				fmt.Fprintf(os.Stderr, "\nWARNING: Application %q already exists in provided configuration files. Not generating new Application.\n\n", appName)
			}
		}
	}

	if namespace != "" && namespace != "default" {
		ok, err := resource.HasObject(ctx, objs, "Namespace", namespace)
		if err != nil {
			return fmt.Errorf("failed to check if Namespace %q exists: %v", namespace, err)
		}
		if !ok {
			fmt.Printf("Creating suggested Namespace configuration file %q\n", namespace)
			nsObj, err := resource.CreateNamespaceObject(ctx, namespace)
			if err != nil {
				return fmt.Errorf("failed to create Namespace object: %v", err)
			}
			objs = append(objs, nsObj)
		}
	}

	for _, obj := range objs {
		if resource.ObjectKind(obj) != "Namespace" {
			if appName != "" {
				if err := resource.AddLabel(ctx, obj, appNameLabelKey, appName, false); err != nil {
					return fmt.Errorf("failed to add %s=%s label to object %v: %v", appNameLabelKey, appName, obj, err)
				}
			}
		}
	}

	var toGcs bool
	var gcsPath string
	if len(objs) > 0 {
		fmt.Printf("Saving suggested configuration files to %q\n", suggestedOutput)
		var lineComments map[string]string
		if im != nil {
			lineComments = map[string]string{
				fmt.Sprintf("image: %s", image.Name(im)): "Will be set to actual image before deployment",
			}
		}

		if strings.HasPrefix(suggestedOutput, "gs://") {
			tmpDir, err := d.Clients.OS.TempDir(ctx, "", k8sConfigStagingDir)
			if err != nil {
				return fmt.Errorf("failed to create tmp directory: %v", err)
			}
			defer d.Clients.OS.RemoveAll(ctx, tmpDir)
			gcsPath = strings.Join([]string{suggestedOutput, suggestedFileName}, "/")
			suggestedOutput = tmpDir
			toGcs = true
		}

		fileName, err := resource.SaveAsConfigs(ctx, objs, suggestedOutput, lineComments, d.Clients.OS)
		if err != nil {
			return fmt.Errorf("failed to save suggested configuration files to %q: %v", suggestedOutput, err)
		}

		if toGcs {
			err := ss.Upload(ctx, fileName, gcsPath)
			if err != nil {
				return fmt.Errorf("failed to upload configuration files from GCS %q: %v", config, err)
			}
		}
	}

	fmt.Printf("\nExpanding configuration files.\n")

	if im != nil {
		imageName := image.Name(im)
		imageDigest, err := image.ResolveDigest(ctx, im, d.Clients.Remote)
		if err != nil {
			return fmt.Errorf("failed to get image digest: %v", err)
		}
		imageWithDigest := fmt.Sprintf("%s@%s", image.Name(im), imageDigest)
		fmt.Printf("Got digest for image: %s --> %s\n", im, imageWithDigest)

		fmt.Printf("Updating containers in configuration files that have image name %q to use image with digest %q\n", imageName, imageWithDigest)
		if err := resource.UpdateMatchingContainerImage(ctx, objs, imageName, imageWithDigest); err != nil {
			return fmt.Errorf("failed to update container of objects: %v", err)
		}
	}

	if namespace != "" {
		if err := resource.UpdateNamespace(ctx, objs, namespace); err != nil {
			return fmt.Errorf("failed to update namespace of objects: %v", err)
		}
	} else {
		if err := resource.AddNamespaceIfMissing(objs, "default"); err != nil {
			return fmt.Errorf("failed to update namespace of objects with no namespace to default: %v", err)
		}
	}

	for _, obj := range objs {
		if resource.ObjectKind(obj) != "Namespace" {
			if appVersion != "" {
				if err := resource.AddLabel(ctx, obj, appVersionLabelKey, appVersion, false); err != nil {
					return fmt.Errorf("failed to add %s=%s label to object %v: %v", appVersionLabelKey, appVersion, obj, err)
				}
			}
		}

		if err := resource.AddLabel(ctx, obj, managedByLabelKey, managedByLabelValue, true); err != nil {
			return fmt.Errorf("failed to add %s=%s label to object %v: %v", managedByLabelKey, managedByLabelValue, obj, err)
		}

		for k, v := range labels {
			if k == appNameLabelKey {
				return fmt.Errorf("%s label must be set using the --app|-a flag", appNameLabelKey)
			}
			if k == appVersionLabelKey {
				return fmt.Errorf("%s label must be set using the --version|-v flag", appVersionLabelKey)
			}
			if k == managedByLabelKey {
				return fmt.Errorf("%s label cannot be explicitly set", managedByLabelKey)
			}

			if err := resource.AddLabel(ctx, obj, k, v, true); err != nil {
				return fmt.Errorf("failed to add %s=%s custom label to object %v: %v", k, v, obj, err)
			}
		}

		for k, v := range annotations {
			if err := resource.AddAnnotation(obj, k, v); err != nil {
				return fmt.Errorf("failed to add %s=%s custom annotation to object %v: %v", k, v, obj, err)
			}
		}

		if resource.ObjectKind(obj) == "Application" {
			if err := resource.SetApplicationLinks(obj, applicationLinks); err != nil {
				return fmt.Errorf("failed to add links to Application: %v", err)
			}
		}
	}

	fmt.Printf("Saving expanded configuration files to %q\n", expandedOutput)

	if strings.HasPrefix(expandedOutput, "gs://") {
		tmpDir, err := d.Clients.OS.TempDir(ctx, "", k8sConfigStagingDir)
		if err != nil {
			return fmt.Errorf("failed to create tmp directory: %v", err)
		}
		defer d.Clients.OS.RemoveAll(ctx, tmpDir)
		gcsPath = strings.Join([]string{expandedOutput, expendedFileName}, "/")
		expandedOutput = tmpDir
		toGcs = true
	}

	fileName, err := resource.SaveAsConfigs(ctx, objs, expandedOutput, nil, d.Clients.OS)
	if err != nil {
		return fmt.Errorf("failed to save expanded configuration files to %q: %v", expandedOutput, err)
	}

	if toGcs {
		err := ss.Upload(ctx, fileName, gcsPath)
		if err != nil {
			return fmt.Errorf("failed to upload configuration files from GCS %q: %v", config, err)
		}
	}

	fmt.Printf("Finished preparing deployment.\n\n")

	return nil
}