in e2etest/newe2e_task_runazcopy.go [317:518]
func RunAzCopy(a ScenarioAsserter, commandSpec AzCopyCommand) (AzCopyStdout, *AzCopyJobPlan) {
if a.Dryrun() {
return nil, &AzCopyJobPlan{}
}
a.HelperMarker().Helper()
var flagMap map[string]string
var envMap map[string]string
// we have no need to update our context manager, Fetch should do it for us.
envCtx := FetchAzCopyEnvironmentContext(a)
envCtx.SetupCleanup(a) // Make sure we add the cleanup hook; the sync.Once ensures idempotency.
// register our environment, or create a new one if needed.
var runNum uint
if env := commandSpec.Environment; env == nil {
commandSpec.Environment = envCtx.CreateEnvironment()
} else {
runNum = envCtx.RegisterEnvironment(env)
}
ctx := context.WithValue(envCtx, AzCopyRunNumKey{}, runNum)
ctx = context.WithValue(ctx, AzCopyEnvironmentKey{}, commandSpec.Environment)
// separate these from the struct so their execution order is fixed
// Setup the positional args
args := func() []string {
if commandSpec.Environment == nil {
commandSpec.Environment = &AzCopyEnvironment{}
}
out := []string{GlobalConfig.AzCopyExecutableConfig.ExecutablePath}
out = append(out, strings.Split(string(commandSpec.Verb), " ")...)
for _, v := range commandSpec.PositionalArgs {
out = append(out, v)
}
for _, v := range commandSpec.Targets {
out = append(out, commandSpec.applyTargetAuth(a, v))
}
if commandSpec.Flags == nil {
switch commandSpec.Verb {
case AzCopyVerbCopy:
commandSpec.Flags = CopyFlags{}
case AzCopyVerbSync:
commandSpec.Flags = SyncFlags{}
case AzCopyVerbList:
commandSpec.Flags = ListFlags{}
case AzCopyVerbLogin:
commandSpec.Flags = LoginFlags{}
case AzCopyVerbLoginStatus:
commandSpec.Flags = LoginStatusFlags{}
case AzCopyVerbRemove:
commandSpec.Flags = RemoveFlags{}
default:
commandSpec.Flags = GlobalFlags{}
}
}
flagMap = MapFromTags(reflect.ValueOf(commandSpec.Flags), "flag", a, ctx)
for k, v := range flagMap {
out = append(out, fmt.Sprintf("--%s=%s", k, v))
}
return out
}()
// Setup the env vars
env := func() []string {
out := make([]string, 0)
envMap = MapFromTags(reflect.ValueOf(commandSpec.Environment), "env", a, ctx)
for k, v := range envMap {
out = append(out, fmt.Sprintf("%s=%s", k, v))
}
if commandSpec.Environment.InheritEnvironment != nil {
ieMap := commandSpec.Environment.InheritEnvironment
if ieMap["*"] {
out = append(out, os.Environ()...)
} else {
for _, v := range os.Environ() {
key := v[:strings.Index(v, "=")]
if ieMap[strings.ToLower(key)] {
out = append(out, v)
}
}
}
}
return out
}()
var out = commandSpec.Stdout
if out == nil { // Select the correct stdoutput parser
switch {
// Dry-run parser
case strings.EqualFold(flagMap["dry-run"], "true") && (strings.EqualFold(flagMap["output-type"], "json") || strings.EqualFold(flagMap["output-type"], "text") || flagMap["output-type"] == ""): // Dryrun has its own special sort of output, that supports non-json output.
jsonMode := strings.EqualFold(flagMap["output-type"], "json")
var fromTo common.FromTo
if !jsonMode && len(commandSpec.Targets) >= 2 {
fromTo = common.FromTo(commandSpec.Targets[0].Location())<<8 | common.FromTo(commandSpec.Targets[1].Location())
}
out = &AzCopyParsedDryrunStdout{
JsonMode: jsonMode,
fromTo: fromTo,
Raw: make(map[string]bool),
}
// Text formats don't get parsed usually
case !strings.EqualFold(flagMap["output-type"], "json"):
out = &AzCopyRawStdout{}
// Copy/sync/remove share the same output format
case commandSpec.Verb == AzCopyVerbCopy || commandSpec.Verb == AzCopyVerbSync || commandSpec.Verb == AzCopyVerbRemove:
out = &AzCopyParsedCopySyncRemoveStdout{
JobPlanFolder: *commandSpec.Environment.JobPlanLocation,
LogFolder: *commandSpec.Environment.LogLocation,
}
// List
case commandSpec.Verb == AzCopyVerbList:
out = &AzCopyParsedListStdout{}
// Jobs list
case commandSpec.Verb == AzCopyVerbJobsList:
out = &AzCopyParsedJobsListStdout{}
// Jobs resume
case commandSpec.Verb == AzCopyVerbJobsResume:
out = &AzCopyParsedCopySyncRemoveStdout{ // Resume command treated the same as copy/sync/remove
JobPlanFolder: *commandSpec.Environment.JobPlanLocation,
LogFolder: *commandSpec.Environment.LogLocation,
}
// Login status
case commandSpec.Verb == AzCopyVerbLoginStatus:
out = &AzCopyParsedLoginStatusStdout{}
// Login (interactive)
case commandSpec.Verb == AzCopyVerbLogin:
var lType common.AutoLoginType
if ltStr := flagMap["login-type"]; ltStr != "" {
_ = lType.Parse(ltStr)
}
if lType.IsInteractive() {
out = NewAzCopyInteractiveStdout(a)
break
}
fallthrough
default: // We don't know how to parse this.
out = &AzCopyRawStdout{}
}
}
stderr := &bytes.Buffer{}
command := exec.Cmd{
Path: GlobalConfig.AzCopyExecutableConfig.ExecutablePath,
Args: args,
Env: env,
Stdout: out, // todo
Stderr: stderr,
}
in, err := command.StdinPipe()
a.NoError("get stdin pipe", err)
err = command.Start()
a.Assert("run command", IsNil{}, err)
if isLaunchedByDebugger {
beginAzCopyDebugging(in)
}
err = command.Wait()
a.Assert("wait for finalize", common.Iff[Assertion](commandSpec.ShouldFail, Not{IsNil{}}, IsNil{}), err)
a.Assert("expected exit code",
common.Iff[Assertion](commandSpec.ShouldFail, Not{Equal{}}, Equal{}),
0, command.ProcessState.ExitCode())
// validate log file retention for jobs clean command before the job logs are cleaned up and uploaded
if !a.Failed() && commandSpec.Verb == AzCopyVerbJobsClean {
ValidateLogFileRetention(a, *commandSpec.Environment.LogLocation, 1)
}
// The environment manager will handle cleanup for us-- All we need to do at this point is register our stdout.
envCtx.RegisterLogUpload(LogUpload{
EnvironmentID: *commandSpec.Environment.EnvironmentId,
RunID: runNum,
Stdout: out.String(),
Stderr: stderr.String(),
})
return out, &AzCopyJobPlan{}
}