You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: provisioner.go
    path of file: ./repos/juju/apiserver/facades/controller/caasunitprovisioner
    
    the code of the file until where you have to start completion: // Copyright 2017 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package caasunitprovisioner

import (
	"fmt"
	"sort"
	"time"

	"github.com/juju/charm/v12"
	"github.com/juju/clock"
	"github.com/juju/collections/set"
	"github.com/juju/errors"
	"github.com/juju/loggo"
	"github.com/juju/names/v5"

	"github.com/juju/juju/apiserver/common"
	charmscommon "github.com/juju/juju/apiserver/common/charms"
	"github.com/juju/juju/apiserver/common/storagecommon"
	apiservererrors "github.com/juju/juju/apiserver/errors"
	"github.com/juju/juju/apiserver/facade"
	"github.com/juju/juju/apiserver/facades/client/application"
	"github.com/juju/juju/apiserver/facades/controller/caasoperatorprovisioner"
	k8sconstants "github.com/juju/juju/caas/kubernetes/provider/constants"
	"github.com/juju/juju/cloudconfig/podcfg"
	"github.com/juju/juju/controller"
	"github.com/juju/juju/core/status"
	"github.com/juju/juju/docker"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/environs/tags"
	"github.com/juju/juju/rpc/params"
	"github.com/juju/juju/state"
	stateerrors "github.com/juju/juju/state/errors"
	"github.com/juju/juju/state/watcher"
	"github.com/juju/juju/storage"
	"github.com/juju/juju/storage/poolmanager"
)

var logger = loggo.GetLogger("juju.apiserver.controller.caasunitprovisioner")

type Facade struct {
	*common.LifeGetter
	entityWatcher   *common.AgentEntityWatcher
	charmInfoAPI    *charmscommon.CharmInfoAPI
	appCharmInfoAPI *charmscommon.ApplicationCharmInfoAPI

	resources          facade.Resources
	state              CAASUnitProvisionerState
	storage            StorageBackend
	storagePoolManager poolmanager.PoolManager
	registry           storage.ProviderRegistry
	devices            DeviceBackend
	clock              clock.Clock
}

// NewFacade returns a new CAAS unit provisioner Facade facade.
func NewFacade(
	resources facade.Resources,
	authorizer facade.Authorizer,
	st CAASUnitProvisionerState,
	sb StorageBackend,
	db DeviceBackend,
	storagePoolManager poolmanager.PoolManager,
	registry storage.ProviderRegistry,
	charmInfoAPI *charmscommon.CharmInfoAPI,
	appCharmInfoAPI *charmscommon.ApplicationCharmInfoAPI,
	clock clock.Clock,
) (*Facade, error) {
	if !authorizer.AuthController() {
		return nil, apiservererrors.ErrPerm
	}
	accessApplication := common.AuthFuncForTagKin
    
func (f *Facade) provisioningInfo(model Model, tagString string) (*params.KubernetesProvisioningInfo, error) {
	appTag, err := names.ParseApplicationTag(tagString)
	if err != nil {
		return nil, errors.Trace(err)
	}
	// First the pod spec.
	podSpec, err := model.PodSpec(appTag)
	if err != nil {
		return nil, errors.Trace(err)
	}
	rawSpec, err := model.RawK8sSpec(appTag)
	if err != nil {
		return nil, errors.Trace(err)
	}
	if podSpec != "" && rawSpec != "" {
		// This should never happen.
		return nil, errors.New("both k8s spec and raw k8s spec were set")
	}

	// Now get any required storage. We need to provision storage
	// at the same time as the pod as it can't be attached later.

	// All units are currently homogeneous so we just
	// need to get info for the first alive unit.
	app, err := f.state.Application(appTag.Id())
	if err != nil {
		return nil, errors.Trace(err)
	}
	modelConfig, err := model.ModelConfig()
	if err != nil {
		return nil, errors.Trace(err)
	}

	controllerCfg, err := f.state.ControllerConfig()
	if err != nil {
		return nil, errors.Trace(err)
	}
	vers, ok := modelConfig.AgentVersion()
	if !ok {
		return nil, errors.NewNotValid(nil,
			fmt.Sprintf("agent version is missing in model config %q", modelConfig.Name()),
		)
	}
	registryPath, err := podcfg.GetJujuOCIImagePath(controllerCfg, vers)
	if err != nil {
		return nil, errors.Trace(err)
	}

	imageRepoDetails, err := docker.NewImageRepoDetails(controllerCfg.CAASImageRepo())
	if err != nil {
		return nil, errors.Annotatef(err, "parsing %s", controller.CAASImageRepo)
	}
	imageRepo := params.NewDockerImageInfo(imageRepoDetails, registryPath)
	logger.Tracef("imageRepo %v", imageRepo)
	filesystemParams, err := f.applicationFilesystemParams(app, controllerCfg, modelConfig)
	if err != nil {
		return nil, errors.Trace(err)
	}

	devices, err := f.devicesParams(app)
	if err != nil {
		return nil, errors.Trace(err)
	}
	cons, err := app.Constraints()
	if err != nil {
		return nil, errors.Trace(err)
	}
	mergedCons, err := f.state.ResolveConstraints(cons)
	if err != nil {
		return nil, errors.Trace(err)
	}
	resourceTags := tags.ResourceTags(
		names.NewModelTag(modelConfig.UUID()),
		names.NewControllerTag(controllerCfg.ControllerUUID()),
		modelConfig,
	)

	ch, _, err := app.Charm()
	if err != nil {
		return nil, errors.Trace(err)
	}

	info := &params.KubernetesProvisioningInfo{
		PodSpec:              podSpec,
		RawK8sSpec:           rawSpec,
		Filesystems:          filesystemParams,
		Devices:              devices,
		Constraints:          mergedCons,
		Tags:                 resourceTags,
		CharmModifiedVersion: app.CharmModifiedVersion(),
		ImageRepo:            imageRepo,
	}
	deployInfo := ch.Meta().Deployment
	if deployInfo != nil {
		info.DeploymentInfo = &params.KubernetesDeploymentInfo{
			DeploymentType: string(deployInfo.DeploymentType),
			ServiceType:    string(deployInfo.ServiceType),
		}
	}
	return info, nil
}