in internal/pkg/cli/run_local.go [153:311]
func newRunLocalOpts(vars runLocalVars) (*runLocalOpts, error) {
sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("run local"))
defaultSess, err := sessProvider.Default()
if err != nil {
return nil, err
}
store := config.NewSSMStore(identity.New(defaultSess), sdkssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region))
deployStore, err := deploy.NewStore(sessProvider, store)
if err != nil {
return nil, err
}
ws, err := workspace.Use(afero.NewOsFs())
if err != nil {
return nil, err
}
labeledTermPrinter := func(fw syncbuffer.FileWriter, bufs []*syncbuffer.LabeledSyncBuffer, opts ...syncbuffer.LabeledTermPrinterOption) clideploy.LabeledTermPrinter {
return syncbuffer.NewLabeledTermPrinter(fw, bufs, opts...)
}
o := &runLocalOpts{
runLocalVars: vars,
sel: selector.NewDeploySelect(prompt.New(), store, deployStore),
store: store,
ws: ws,
newInterpolator: newManifestInterpolator,
sessProvider: sessProvider,
unmarshal: manifest.UnmarshalWorkload,
sess: defaultSess,
cmd: exec.NewCmd(),
dockerEngine: dockerengine.New(exec.NewCmd()),
labeledTermPrinter: labeledTermPrinter,
prog: termprogress.NewSpinner(log.DiagnosticWriter),
}
o.configureClients = func() error {
defaultSessEnvRegion, err := o.sessProvider.DefaultWithRegion(o.targetEnv.Region)
if err != nil {
return fmt.Errorf("create default session with region %s: %w", o.targetEnv.Region, err)
}
o.envManagerSess, err = o.sessProvider.FromRole(o.targetEnv.ManagerRoleARN, o.targetEnv.Region)
if err != nil {
return fmt.Errorf("create env manager session %s: %w", o.targetEnv.Region, err)
}
// EnvManagerRole has permissions to get task def and get SSM values.
// However, it doesn't have permissions to get secrets from secrets manager,
// so use the default sess and *hope* they have permissions.
o.ecsClient = ecs.New(o.envManagerSess)
o.ssm = ssm.New(o.envManagerSess)
o.ecsExecutor = awsecs.New(o.envManagerSess)
o.secretsManager = secretsmanager.New(defaultSessEnvRegion)
resources, err := cloudformation.New(o.sess, cloudformation.WithProgressTracker(os.Stderr)).GetAppResourcesByRegion(o.targetApp, o.targetEnv.Region)
if err != nil {
return fmt.Errorf("get application %s resources from region %s: %w", o.appName, o.envName, err)
}
repoName := clideploy.RepoName(o.appName, o.wkldName)
o.repository = repository.NewWithURI(ecr.New(defaultSessEnvRegion), repoName, resources.RepositoryURLs[o.wkldName])
idPrefix := fmt.Sprintf("%s-%s-%s-", o.appName, o.envName, o.wkldName)
colorGen := termcolor.ColorGenerator()
o.orchestrator = orchestrator.New(o.dockerEngine, idPrefix, func(name string, ctr orchestrator.ContainerDefinition) dockerengine.RunLogOptions {
return dockerengine.RunLogOptions{
Color: colorGen(),
Output: os.Stderr,
LinePrefix: fmt.Sprintf("[%s] ", name),
}
})
o.hostFinder = &hostDiscoverer{
app: o.appName,
env: o.envName,
wkld: o.wkldName,
ecs: ecs.New(o.envManagerSess),
rg: resourcegroups.New(o.envManagerSess),
rds: rds.New(o.envManagerSess),
}
envDesc, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{
App: o.appName,
Env: o.envName,
ConfigStore: store,
})
if err != nil {
return fmt.Errorf("create env describer: %w", err)
}
o.envChecker = envDesc
return nil
}
o.buildContainerImages = func(mft manifest.DynamicWorkload) (map[string]string, error) {
if dockerWkld, ok := mft.Manifest().(dockerWorkload); ok {
dfDir := filepath.Dir(dockerWkld.Dockerfile())
o.dockerExcludes, err = dockerfile.ReadDockerignore(afero.NewOsFs(), filepath.Join(ws.Path(), dfDir))
if err != nil {
return nil, err
}
o.filterDockerExcludes()
}
gitShortCommit := imageTagFromGit(o.cmd)
image := clideploy.ContainerImageIdentifier{
GitShortCommitTag: gitShortCommit,
}
out := &clideploy.UploadArtifactsOutput{}
if err := clideploy.BuildContainerImages(&clideploy.ImageActionInput{
Name: o.wkldName,
WorkspacePath: o.ws.Path(),
Image: image,
Mft: mft.Manifest(),
GitShortCommitTag: gitShortCommit,
Builder: o.repository,
Login: o.repository.Login,
CheckDockerEngine: o.dockerEngine.CheckDockerEngineRunning,
LabeledTermPrinter: o.labeledTermPrinter,
}, out); err != nil {
return nil, err
}
containerURIs := make(map[string]string, len(out.ImageDigests))
for name, info := range out.ImageDigests {
if len(info.RepoTags) == 0 {
// this shouldn't happen, but just to avoid a panic in case
return nil, fmt.Errorf("no repo tags for image %q", name)
}
containerURIs[name] = info.RepoTags[0]
}
return containerURIs, nil
}
o.debounceTime = 5 * time.Second
o.newRecursiveWatcher = func() (recursiveWatcher, error) {
return file.NewRecursiveWatcher(0)
}
// Capture stdout by replacing it with a piped writer and returning an attached io.Reader.
// Functions are concurrency safe and idempotent.
var mu sync.Mutex
var savedWriter, savedStdout *os.File
savedStdout = os.Stdout
o.captureStdout = func() (io.Reader, error) {
if savedWriter != nil {
savedWriter.Close()
}
pipeReader, pipeWriter, err := os.Pipe()
if err != nil {
return nil, err
}
mu.Lock()
defer mu.Unlock()
savedWriter = pipeWriter
os.Stdout = savedWriter
return (io.Reader)(pipeReader), nil
}
o.releaseStdout = func() {
mu.Lock()
defer mu.Unlock()
os.Stdout = savedStdout
savedWriter.Close()
}
return o, nil
}