func (p *Platform) GetName() string {
	return "local"
}
GetName returns the platform name
package local
import (
	"bytes"
	"context"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strconv"
	"time"
	"github.com/nuclio/nuclio/pkg/cmdrunner"
	"github.com/nuclio/nuclio/pkg/common"
	"github.com/nuclio/nuclio/pkg/containerimagebuilderpusher"
	"github.com/nuclio/nuclio/pkg/dockerclient"
	"github.com/nuclio/nuclio/pkg/functionconfig"
	"github.com/nuclio/nuclio/pkg/opa"
	"github.com/nuclio/nuclio/pkg/platform"
	"github.com/nuclio/nuclio/pkg/platform/abstract"
	"github.com/nuclio/nuclio/pkg/platform/abstract/project"
	externalproject "github.com/nuclio/nuclio/pkg/platform/abstract/project/external"
	"github.com/nuclio/nuclio/pkg/platform/abstract/project/internalc/local"
	"github.com/nuclio/nuclio/pkg/platform/local/client"
	"github.com/nuclio/nuclio/pkg/platformconfig"
	"github.com/nuclio/nuclio/pkg/processor"
	"github.com/nuclio/nuclio/pkg/processor/config"
	"github.com/ghodss/yaml"
	"github.com/nuclio/errors"
	"github.com/nuclio/logger"
	"github.com/nuclio/nuclio-sdk-go"
	"github.com/nuclio/zap"
)
type Platform struct {
	*abstract.Platform
	cmdRunner                cmdrunner.CmdRunner
	dockerClient             dockerclient.Client
	localStore               *client.Store
	defaultFunctionMountMode FunctionMountMode
	projectsClient           project.Client
}
const Mib = 1048576
const FunctionProcessorContainerDirPath = "/etc/nuclio/config/processor"
func NewProjectsClient(platform *Platform, platformConfiguration *platformconfig.Config) (project.Client, error) {
	localProjectsClient, err := local.NewClient(platform.Logger, platform, platform.localStore)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to create internal projects client (local)")
	}
	if platformConfiguration.ProjectsLeader != nil {
		return externalproject.NewClient(platform.Logger, localProjectsClient, platformConfiguration)
	}
	return localProjectsClient, nil
}
func NewPlatform(parentLogger logger.Logger,
	platformConfiguration *platformconfig.Config,
	defaultNamespace string) (*Platform, error) {
	newPlatform := &Platform{}
	newAbstractPlatform, err := abstract.NewPlatform(parentLogger, newPlatform, platformConfiguration, defaultNamespace)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to create an abstract platform")
	}
	newPlatform.Platform = newAbstractPlatform
	if newPlatform.cmdRunner, err = cmdrunner.NewShellRunner(newPlatform.Logger); err != nil {
		return nil, errors.Wrap(err, "Failed to create a command runner")
	}
	if newPlatform.ContainerBuilder, err = containerimagebuilderpusher.NewDocker(newPlatform.Logger,
		platformConfiguration.ContainerBuilderConfiguration); err != nil {
		return nil, errors.Wrap(err, "Failed to create containerimagebuilderpusher")
	}
	if newPlatform.dockerClient, err = dockerclient.NewShellClient(newPlatform.Logger, nil); err != nil {
		return nil, errors.Wrap(err, "Failed to create a Docker client")
	}
	if newPlatform.localStore, err = client.NewStore(parentLogger, newPlatform, newPlatform.dockerClient); err != nil {
		return nil, errors.Wrap(err, "Failed to create a local store")
	}
	newPlatform.projectsClient, err = NewProjectsClient(newPlatform, platformConfiguration)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to create projects client")
	}
	if newPlatform.Config.Local.FunctionContainersHealthinessEnabled {
		newPlatform.Logger.DebugWith("Igniting container healthiness validator")
		go func(newPlatform *Platform) {
			uptimeTicker := time.NewTicker(newPlatform.Config.Local.FunctionContainersHealthinessInterval)
			for range uptimeTicker.C {
				newPlatform.ValidateFunctionContainersHealthiness()
			}
		}(newPlatform)
	}
	newPlatform.defaultFunctionMountMode = FunctionMountMode(
		common.GetEnvOrDefaultString("NUCLIO_DASHBOARD_DEFAULT_FUNCTION_MOUNT_MODE", string(FunctionMountModeBind)),
	)
	return newPlatform, nil
}
func (p *Platform) Initialize() error {
	if err := p.projectsClient.Initialize(); err != nil {
		return errors.Wrap(err, "Failed to initialize projects client")
	}
	if p.Config.ProjectsLeader == nil {
		if err := p.EnsureDefaultProjectExistence(); err != nil {
			return errors.Wrap(err, "Failed to ensure default project existence")
		}
	}
	return nil
}
func (p *Platform) CreateFunction(createFunctionOptions *platform.CreateFunctionOptions) (*platform.CreateFunctionResult, error) {
	var previousHTTPPort int
	var err error
	var existingFunctionConfig *functionconfig.ConfigWithStatus
	if err := p.enrichAndValidateFunctionConfig(&createFunctionOptions.FunctionConfig); err != nil {
		return nil, errors.Wrap(err, "Failed to enrich and validate a function configuration")
	}
	permissionOptions := createFunctionOptions.PermissionOptions
	permissionOptions.RaiseForbidden = true
	if _, err := p.QueryOPAFunctionPermissions(createFunctionOptions.FunctionConfig.Meta.Labels[common.NuclioResourceLabelKeyProjectName],
		createFunctionOptions.FunctionConfig.Meta.Name,
		opa.ActionCreate,
		&permissionOptions); err != nil {
		return nil, errors.Wrap(err, "Failed authorizing OPA permissions for resource")
	}
	createFunctionOptions.FunctionConfig.Spec.RunRegistry = ""
	createFunctionOptions.FunctionConfig.Spec.Build.Registry = ""
	if createFunctionOptions.FunctionConfig.Meta.Namespace != "" && createFunctionOptions.FunctionConfig.Meta.Name != "" {
		existingFunctions, err := p.localStore.GetFunctions(&createFunctionOptions.FunctionConfig.Meta)
		if err != nil {
			return nil, errors.Wrap(err, "Failed to get existing functions")
		}
		if len(existingFunctions) == 0 {
			existingFunctionConfig = nil
		} else {
			existingFunction := existingFunctions[0]
			existingFunctionConfig = &functionconfig.ConfigWithStatus{
				Config: *existingFunction.GetConfig(),
				Status: *existingFunction.GetStatus(),
			}
		}
	}
	if err := p.ValidateCreateFunctionOptionsAgainstExistingFunctionConfig(existingFunctionConfig,
		createFunctionOptions); err != nil {
		return nil, errors.Wrap(err, "Failed to validate a function configuration against an existing configuration")
	}
	logStream, err := abstract.NewLogStream("deployer", nucliozap.InfoLevel, createFunctionOptions.Logger)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to create a log stream")
	}
	p.DeployLogStreams.Store(createFunctionOptions.FunctionConfig.Meta.GetUniqueID(), logStream)
	createFunctionOptions.Logger = logStream.GetLogger()
	reportCreationError := func(creationError error) error {
		createFunctionOptions.Logger.WarnWith("Failed to create a function; setting the function status",
			"err", creationError)
		errorStack := bytes.Buffer{}
		errors.PrintErrorStack(&errorStack, creationError, 20)
		if errorStack.Len() >= 4*Mib {
			errorStack.Truncate(4 * Mib)
		}
		return p.localStore.CreateOrUpdateFunction(&functionconfig.ConfigWithStatus{
			Config: createFunctionOptions.FunctionConfig,
			Status: functionconfig.Status{
				State:   functionconfig.FunctionStateError,
				Message: errorStack.String(),
			},
		})
	}
	onAfterConfigUpdated := func() error {
		createFunctionOptions.Logger.DebugWith("Creating shadow function",
			"name", createFunctionOptions.FunctionConfig.Meta.Name)
		if err := p.enrichAndValidateFunctionConfig(&createFunctionOptions.FunctionConfig); err != nil {
			return errors.Wrap(err, "Failed to enrich and validate the updated function configuration")
		}
		if err := p.localStore.CreateOrUpdateFunction(&functionconfig.ConfigWithStatus{
			Config: createFunctionOptions.FunctionConfig,
			Status: functionconfig.Status{
				State: functionconfig.FunctionStateBuilding,
			},
		}); err != nil {
			return errors.Wrap(err, "Failed to create a function")
		}
		previousHTTPPort, err = p.deletePreviousContainers(createFunctionOptions)
		if err != nil {
			return errors.Wrap(err, "Failed to delete previous containers")
		}
		if createFunctionOptions.CreationStateUpdated != nil {
			createFunctionOptions.CreationStateUpdated <- true
		}
		return nil
	}
	onAfterBuild := func(buildResult *platform.CreateFunctionBuildResult, buildErr error) (*platform.CreateFunctionResult, error) {
		if buildErr != nil {
			reportCreationError(buildErr)  
			return nil, buildErr
		}
		skipFunctionDeploy := functionconfig.ShouldSkipDeploy(createFunctionOptions.FunctionConfig.Meta.Annotations)
		createFunctionOptions.FunctionConfig.Meta.RemoveSkipDeployAnnotation()
		createFunctionOptions.FunctionConfig.Meta.RemoveSkipBuildAnnotation()
		var createFunctionResult *platform.CreateFunctionResult
		var deployErr error
		var functionStatus functionconfig.Status
		if !skipFunctionDeploy {
			createFunctionResult, deployErr = p.deployFunction(createFunctionOptions, previousHTTPPort)
			if deployErr != nil {
				reportCreationError(deployErr)  
				return nil, deployErr
			}
			functionStatus.HTTPPort = createFunctionResult.Port
			functionStatus.State = functionconfig.FunctionStateReady
			if err := p.populateFunctionInvocationStatus(&functionStatus, createFunctionResult); err != nil {
				return nil, errors.Wrap(err, "Failed to populate function invocation status")
			}
		} else {
			p.Logger.Info("Skipping function deployment")
			functionStatus.State = functionconfig.FunctionStateImported
			createFunctionResult = &platform.CreateFunctionResult{
				CreateFunctionBuildResult: platform.CreateFunctionBuildResult{
					Image:                 createFunctionOptions.FunctionConfig.Spec.Image,
					UpdatedFunctionConfig: createFunctionOptions.FunctionConfig,
				},
			}
		}
		if err := p.localStore.CreateOrUpdateFunction(&functionconfig.ConfigWithStatus{
			Config: createFunctionOptions.FunctionConfig,
			Status: functionStatus,
		}); err != nil {
			return nil, errors.Wrap(err, "Failed to update a function with state")
		}
		createFunctionResult.FunctionStatus = functionStatus
		return createFunctionResult, nil
	}
	if createFunctionOptions.InputImageFile != "" {
		p.Logger.InfoWith("Loading docker image from archive",
			"input", createFunctionOptions.InputImageFile)
		if err := p.dockerClient.Load(createFunctionOptions.InputImageFile); err != nil {
			return nil, errors.Wrap(err, "Failed to load a Docker image from an archive")
		}
	}
	return p.HandleDeployFunction(existingFunctionConfig, createFunctionOptions, onAfterConfigUpdated, onAfterBuild)
}
func (p *Platform) GetFunctions(getFunctionsOptions *platform.GetFunctionsOptions) ([]platform.Function, error) {
	projectName, err := p.Platform.ResolveProjectNameFromLabelsStr(getFunctionsOptions.Labels)
	if err != nil {
		return nil, errors.Wrap(err, "")
	}
	if err := p.Platform.EnsureProjectRead(projectName, &getFunctionsOptions.PermissionOptions); err != nil {
		return nil, errors.Wrap(err, "Failed to ensure project read permission")
	}
	functions, err := p.localStore.GetProjectFunctions(getFunctionsOptions)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to read functions from a local store")
	}
	functions, err = p.Platform.FilterFunctionsByPermissions(&getFunctionsOptions.PermissionOptions, functions)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to filter functions by permissions")
	}
	p.EnrichFunctionsWithDeployLogStream(functions)
	return functions, nil
}
func (p *Platform) UpdateFunction(updateFunctionOptions *platform.UpdateFunctionOptions) error {
	return nil
}
func (p *Platform) DeleteFunction(deleteFunctionOptions *platform.DeleteFunctionOptions) error {
	if err := p.ValidateDeleteFunctionOptions(deleteFunctionOptions); err != nil {
		return errors.Wrap(err, "Failed to validate function-deletion options")
	}
	return p.delete(deleteFunctionOptions)
}
func (p *Platform) GetFunctionReplicaLogsStream(ctx context.Context,
	options *platform.GetFunctionReplicaLogsStreamOptions) (io.ReadCloser, error) {
	sinceDuration := ""
	if options.SinceSeconds != nil {
		sinceDuration = (time.Second * time.Duration(*options.SinceSeconds)).String()
	}
	tail := ""
	if options.TailLines != nil {
		tail = strconv.FormatInt(*options.TailLines, 10)
	}
	return p.dockerClient.GetContainerLogStream(ctx,
		options.Name,
		&dockerclient.ContainerLogsOptions{
			Follow: options.Follow,
			Since:  sinceDuration,
			Tail:   tail,
		})
}
func (p *Platform) GetFunctionReplicaNames(ctx context.Context,
	functionConfig *functionconfig.Config) ([]string, error) {
	return []string{
		p.GetFunctionContainerName(functionConfig),
	}, nil
}
func (p *Platform) GetHealthCheckMode() platform.HealthCheckMode {
	return platform.HealthCheckModeInternalClient
}