func (d *deployCommandeer) getImportedFunction(functionName string) (platform.Function, error) {
	functions, err := d.rootCommandeer.platform.GetFunctions(&platform.GetFunctionsOptions{
		Name:      functionName,
		Namespace: d.rootCommandeer.namespace,
	})
	if err != nil {
		return nil, errors.Wrap(err, "Failed to check existing functions")
	}
	if len(functions) == 0 {
		return nil, nil
	}
	function := functions[0]
	if err := function.Initialize(nil); err != nil {
		d.rootCommandeer.loggerInstance.DebugWith("Failed to initialize function", "err", err.Error())
	}
	if function.GetStatus().State == functionconfig.FunctionStateImported {
		return function, nil
	}
	return nil, nil
}
If user runs deploy with a function name of a function that was already imported, this checks if that function
exists and is imported. If so, returns that function, otherwise returns nil.
package command
import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"github.com/nuclio/nuclio/pkg/common"
	"github.com/nuclio/nuclio/pkg/functionconfig"
	nuctlcommon "github.com/nuclio/nuclio/pkg/nuctl/command/common"
	"github.com/nuclio/nuclio/pkg/platform"
	"github.com/nuclio/nuclio/pkg/platform/abstract"
	"github.com/nuclio/errors"
	"github.com/spf13/cobra"
	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
)
type deployCommandeer struct {
	cmd                             *cobra.Command
	rootCommandeer                  *RootCommandeer
	functionConfig                  functionconfig.Config
	functionBuild                   functionconfig.Build
	functionName                    string
	functionConfigPath              string
	description                     string
	disable                         bool
	publish                         bool
	handler                         string
	runtime                         string
	image                           string
	targetCPU                       int
	runRegistry                     string
	readinessTimeoutSeconds         int
	volumes                         stringSliceFlag
	commands                        stringSliceFlag
	encodedDataBindings             string
	encodedTriggers                 string
	encodedLabels                   string
	encodedAnnotations              string
	encodedRuntimeAttributes        string
	projectName                     string
	resourceLimits                  stringSliceFlag
	resourceRequests                stringSliceFlag
	encodedEnv                      stringSliceFlag
	encodedFunctionPlatformConfig   string
	encodedBuildRuntimeAttributes   string
	encodedBuildCodeEntryAttributes string
	inputImageFile                  string
	loggerLevel                     string
	replicas                        int
	minReplicas                     int
	maxReplicas                     int
	priorityClassName               string
	preemptionPolicy                string
	nodeName                        string
	encodedNodeSelector             string
	runAsUser                       int64
	runAsGroup                      int64
	fsGroup                         int64
	overrideHTTPTriggerServiceType  string
}
func newDeployCommandeer(rootCommandeer *RootCommandeer) *deployCommandeer {
	commandeer := &deployCommandeer{
		rootCommandeer: rootCommandeer,
		functionConfig: *functionconfig.NewConfig(),
	}
	cmd := &cobra.Command{
		Use:   "deploy function-name",
		Short: "Build and deploy a function, or deploy from an existing image",
		RunE: func(cmd *cobra.Command, args []string) error {
			var err error
			if err := rootCommandeer.initialize(); err != nil {
				return errors.Wrap(err, "Failed to initialize root")
			}
			var importedFunction platform.Function
			if len(args) == 1 {
				commandeer.functionName = args[0]
				importedFunction, err = commandeer.getImportedFunction(args[0])
				if err != nil {
					return errors.Wrap(err, "Failed getting the imported function's data")
				}
				if importedFunction != nil {
					commandeer.rootCommandeer.loggerInstance.Debug("Function was already imported, deploying it")
					commandeer.functionConfig = commandeer.prepareFunctionConfigForRedeploy(importedFunction)
				}
			}
			if importedFunction == nil && commandeer.functionConfigPath != "" {
				commandeer.rootCommandeer.loggerInstance.DebugWith("Loading function config from file", "file", commandeer.functionConfigPath)
				functionConfigFile, err := nuctlcommon.OpenFile(commandeer.functionConfigPath)
				if err != nil {
					return errors.Wrap(err, "Failed opening function config file")
				}
				functionBody, err := ioutil.ReadAll(functionConfigFile)
				if err != nil {
					return errors.Wrap(err, "Failed reading function config file")
				}
				unmarshalFunc, err := nuctlcommon.GetUnmarshalFunc(functionBody)
				if err != nil {
					return errors.Wrap(err, "Failed identifying function config file format")
				}
				err = unmarshalFunc(functionBody, &commandeer.functionConfig)
				if err != nil {
					return errors.Wrap(err, "Failed parsing function config file")
				}
				commandeer.rootCommandeer.loggerInstance.DebugWith("Successfully loaded function config", "functionConfig", commandeer.functionConfig)
			}
			commandeer.populateDeploymentDefaults()
			commandeer.populateHTTPServiceType()
			commandeer.functionConfig.Meta.Name = commandeer.functionName
			commandeer.functionConfig.Meta.Namespace = rootCommandeer.namespace
			commandeer.functionConfig.Spec.Build = commandeer.functionBuild
			commandeer.functionConfig.Spec.Build.Commands = commandeer.commands
			commandeer.functionConfig.Spec.Build.FunctionConfigPath = commandeer.functionConfigPath
			commandeer.enrichConfigWithStringArgs()
			commandeer.enrichConfigWithIntArgs()
			commandeer.enrichConfigWithBoolArgs()
			err = commandeer.enrichConfigWithComplexArgs()
			if err != nil {
				return errors.Wrap(err, "Failed config with complex args")
			}
			commandeer.functionConfig.Meta.RemoveSkipBuildAnnotation()
			commandeer.functionConfig.Meta.RemoveSkipDeployAnnotation()
			commandeer.rootCommandeer.loggerInstance.DebugWith("Deploying function", "functionConfig", commandeer.functionConfig)
			_, deployErr := rootCommandeer.platform.CreateFunction(&platform.CreateFunctionOptions{
				Logger:         rootCommandeer.loggerInstance,
				FunctionConfig: commandeer.functionConfig,
				InputImageFile: commandeer.inputImageFile,
			})
			commandeer.rootCommandeer.loggerInstance.Debug("Saving deployment logs")
			logSaveErr := rootCommandeer.platform.SaveFunctionDeployLogs(commandeer.functionName, rootCommandeer.namespace)
			if deployErr != nil {
				return deployErr
			}
			return logSaveErr
		},
	}
	addDeployFlags(cmd, commandeer)
	cmd.Flags().StringVarP(&commandeer.inputImageFile, "input-image-file", "", "", "Path to an input function-image Docker archive file")
	commandeer.cmd = cmd
	return commandeer
}
func addDeployFlags(cmd *cobra.Command,
	commandeer *deployCommandeer) {
	addBuildFlags(cmd, &commandeer.functionBuild, &commandeer.functionConfigPath, &commandeer.runtime, &commandeer.handler, &commandeer.commands, &commandeer.encodedBuildRuntimeAttributes, &commandeer.encodedBuildCodeEntryAttributes)
	cmd.Flags().StringVar(&commandeer.description, "desc", "", "Function description")
	cmd.Flags().StringVarP(&commandeer.encodedLabels, "labels", "l", "", "Additional function labels (lbl1=val1[,lbl2=val2,...])")
	cmd.Flags().StringVar(&commandeer.encodedAnnotations, "annotations", "", "Additional function annotations (ant1=val1[,ant2=val2,...])")
	cmd.Flags().StringVar(&commandeer.encodedNodeSelector, "nodeSelector", "", "Run function pod on a Node by key=value selection constraints (key1=val1[,key2=val2,...])")
	cmd.Flags().StringVar(&commandeer.nodeName, "nodeName", "", "Run function pod on a Node by name-matching selection constrain")
	cmd.Flags().StringVar(&commandeer.priorityClassName, "priorityClassName", "", "Indicates the importance of a function Pod relatively to other function pods")
	cmd.Flags().StringVar(&commandeer.preemptionPolicy, "preemptionPolicy", "", "Function pod preemption policy")
	cmd.Flags().VarP(&commandeer.encodedEnv, "env", "e", "Environment variables env1=val1")
	cmd.Flags().BoolVarP(&commandeer.disable, "disable", "d", false, "Start the function as disabled (don't run yet)")
	cmd.Flags().IntVarP(&commandeer.replicas, "replicas", "", -1, "Set to any non-negative integer to use a static number of replicas")
	cmd.Flags().IntVar(&commandeer.minReplicas, "min-replicas", -1, "Minimal number of function replicas")
	cmd.Flags().IntVar(&commandeer.maxReplicas, "max-replicas", -1, "Maximal number of function replicas")
	cmd.Flags().Int64Var(&commandeer.runAsUser, "run-as-user", -1, "Run function process with user ID")
	cmd.Flags().Int64Var(&commandeer.runAsGroup, "run-as-group", -1, "Run function process with group ID")
	cmd.Flags().Int64Var(&commandeer.fsGroup, "fsgroup", -1, "Run function process with supplementary groups")
	cmd.Flags().IntVar(&commandeer.targetCPU, "target-cpu", -1, "Target CPU-usage percentage when auto-scaling")
	cmd.Flags().BoolVar(&commandeer.publish, "publish", false, "Publish the function")
	cmd.Flags().StringVar(&commandeer.encodedDataBindings, "data-bindings", "", "JSON-encoded data bindings for the function")
	cmd.Flags().StringVar(&commandeer.encodedTriggers, "triggers", "", "JSON-encoded triggers for the function")
	cmd.Flags().StringVar(&commandeer.overrideHTTPTriggerServiceType, "http-trigger-service-type", "", "A Kubernetes ServiceType to apply to the HTTP trigger")
	cmd.Flags().StringVar(&commandeer.encodedFunctionPlatformConfig, "platform-config", "", "JSON-encoded platform specific configuration")
	cmd.Flags().StringVar(&commandeer.image, "run-image", "", "Name of an existing image to deploy (default - build a new image to deploy)")
	cmd.Flags().StringVar(&commandeer.runRegistry, "run-registry", "", "URL of a registry for pulling the image, if differs from -r/--registry (env: NUCTL_RUN_REGISTRY)")
	cmd.Flags().StringVar(&commandeer.encodedRuntimeAttributes, "runtime-attrs", "", "JSON-encoded runtime attributes for the function")
	cmd.Flags().IntVar(&commandeer.readinessTimeoutSeconds, "readiness-timeout", -1, "Maximum wait period for the function to be ready, in seconds")
	cmd.Flags().StringVar(&commandeer.projectName, "project-name", "", "The name of the function's parent project")
	cmd.Flags().Var(&commandeer.volumes, "volume", "Volumes for the deployment function (src1=dest1[,src2=dest2,...])")
	cmd.Flags().Var(&commandeer.resourceLimits, "resource-limit", "Resource restrictions of the format '<resource name>=<quantity>' (for example, 'cpu=3')")
	cmd.Flags().Var(&commandeer.resourceRequests, "resource-request", "Requested resources of the format '<resource name>=<quantity>' (for example, 'cpu=3')")
	cmd.Flags().StringVar(&commandeer.loggerLevel, "logger-level", "", "One of debug, info, warn, error. By default, uses platform configuration")
}
func parseResourceAllocations(values stringSliceFlag, resources *v1.ResourceList) error {
	for _, value := range values {
		resourceNameAndQuantity := strings.Split(value, "=")
		if len(resourceNameAndQuantity) != 2 {
			return errors.Errorf("Resource allocation %s not in the format of resource-name=quantity", value)
		}
		resourceName := v1.ResourceName(resourceNameAndQuantity[0])
		resourceQuantityString := resourceNameAndQuantity[1]
		resourceQuantity, err := resource.ParseQuantity(resourceQuantityString)
		if err != nil {
			return errors.Wrap(err, "Failed to parse quantity")
		}
		if *resources == nil {
			*resources = v1.ResourceList{}
		}
		(*resources)[resourceName] = resourceQuantity
	}
	return nil
}
func parseVolumes(volumes stringSliceFlag) ([]functionconfig.Volume, error) {
	var originVolumes []functionconfig.Volume
	for volumeIndex, volume := range volumes {
		volumeSrcAndDestination := strings.Split(volume, ":")
		if len(volumeSrcAndDestination) != 2 || len(volumeSrcAndDestination[0]) == 0 || len(volumeSrcAndDestination[1]) == 0 {
			return []functionconfig.Volume{}, errors.Errorf("Volume format %s not in the format of volume-src:volume-destination", volumeSrcAndDestination)
		}
		volumeName := fmt.Sprintf("volume-%v", volumeIndex+1)
		originVolumes = append(originVolumes,
			functionconfig.Volume{
				Volume: v1.Volume{
					Name: volumeName,
					VolumeSource: v1.VolumeSource{
						HostPath: &v1.HostPathVolumeSource{
							Path: volumeSrcAndDestination[0],
						},
					},
				},
				VolumeMount: v1.VolumeMount{
					Name:      volumeName,
					MountPath: volumeSrcAndDestination[1],
				},
			},
		)
	}
	return originVolumes, nil
}