diff --git a/container/src/podcvd/internal/const.go b/container/src/podcvd/internal/const.go index bcb24f907e7..a01ca8b4fc8 100644 --- a/container/src/podcvd/internal/const.go +++ b/container/src/podcvd/internal/const.go @@ -28,6 +28,7 @@ const ( labelGroupName = "group_name" labelCreatedBy = "created_by" labelAttemptID = "attempt_id" + labelBaseDir = "base_dir" valueCreatedBy = "podcvd" ToolingContainerName = "tooling" ) diff --git a/container/src/podcvd/internal/cvd.go b/container/src/podcvd/internal/cvd.go index da1f5b168bf..eb4bfc06ba9 100644 --- a/container/src/podcvd/internal/cvd.go +++ b/container/src/podcvd/internal/cvd.go @@ -73,22 +73,22 @@ func ParseInstanceGroups(jsonStr, groupName string) (*InstanceGroup, error) { return &instanceGroup, nil } -func UpdateCvdGroupJsonRaw(data any, podcvdHomeDir, ipAddr string) { +func UpdateCvdGroupJsonRaw(data any, podcvdBaseDir, ipAddr string) { switch v := data.(type) { case map[string]any: for k, val := range v { if s, ok := val.(string); ok { - v[k] = updateStringOnCvdGroupJsonRaw(s, podcvdHomeDir, ipAddr) + v[k] = updateStringOnCvdGroupJsonRaw(s, podcvdBaseDir, ipAddr) } else { - UpdateCvdGroupJsonRaw(val, podcvdHomeDir, ipAddr) + UpdateCvdGroupJsonRaw(val, podcvdBaseDir, ipAddr) } } case []any: for k, val := range v { if s, ok := val.(string); ok { - v[k] = updateStringOnCvdGroupJsonRaw(s, podcvdHomeDir, ipAddr) + v[k] = updateStringOnCvdGroupJsonRaw(s, podcvdBaseDir, ipAddr) } else { - UpdateCvdGroupJsonRaw(val, podcvdHomeDir, ipAddr) + UpdateCvdGroupJsonRaw(val, podcvdBaseDir, ipAddr) } } } @@ -130,11 +130,11 @@ func updateIPAndPortString(data, ipAddr string) string { return data } -var cvdPathRegex = regexp.MustCompile(`^/var/tmp/cvd/[0-9]+/[0-9]+/home`) +var cvdPathRegex = regexp.MustCompile(`^/var/tmp/cvd/[0-9]+/[0-9]+`) -func updateStringOnCvdGroupJsonRaw(data, podcvdHomeDir, ipAddr string) string { +func updateStringOnCvdGroupJsonRaw(data, podcvdBaseDir, ipAddr string) string { data = updateIPAndPortString(data, ipAddr) - return cvdPathRegex.ReplaceAllString(data, podcvdHomeDir) + return cvdPathRegex.ReplaceAllString(data, podcvdBaseDir) } type psColumn struct { diff --git a/container/src/podcvd/internal/host.go b/container/src/podcvd/internal/host.go index 78e6a0bb210..c80109760f6 100644 --- a/container/src/podcvd/internal/host.go +++ b/container/src/podcvd/internal/host.go @@ -264,12 +264,12 @@ func mountablePathsFromConfigFile(cvdArgs *CvdArgs) []string { return extractPaths(data) } -func collectMountSpecs(pathsToMount []string, hostOut, productOut, cvdDataHome, podcvdHomeDir, cacheDir string) []string { +func collectMountSpecs(pathsToMount []string, hostOut, productOut, cvdDataHome, podcvdBaseDir, cacheDir string) []string { bindMap := make(map[string]string) bindMap["/host_out"] = fmt.Sprintf("%s:/host_out:O", hostOut) bindMap["/product_out"] = fmt.Sprintf("%s:/product_out:O", productOut) bindMap["/root/.local/share/cvd"] = fmt.Sprintf("%s:/root/.local/share/cvd:ro", cvdDataHome) - bindMap["/podcvd_home"] = fmt.Sprintf("%s:/podcvd_home:rw", podcvdHomeDir) + bindMap["/podcvd_base"] = fmt.Sprintf("%s:/podcvd_base:rw", podcvdBaseDir) bindMap["/var/tmp/cvd/0/cache"] = fmt.Sprintf("%s:/var/tmp/cvd/0/cache:rw", cacheDir) bindMap["/etc/cuttlefish-common/operator/cert/cert.pem"] = "/etc/cuttlefish-podcvd/cert.pem:/etc/cuttlefish-common/operator/cert/cert.pem:ro" bindMap["/etc/cuttlefish-common/operator/cert/key.pem"] = "/etc/cuttlefish-podcvd/key.pem:/etc/cuttlefish-common/operator/cert/key.pem:ro" @@ -388,7 +388,19 @@ func createAndStartContainer(ccm CuttlefishContainerManager, cvdArgs *CvdArgs) ( if err := os.MkdirAll(podcvdRootDir, 0777); err != nil { return "", fmt.Errorf("failed to create podcvd root dir: %w", err) } - podcvdHomeDir := filepath.Join(podcvdRootDir, strconv.Itoa(os.Getuid()), attemptID) + baseDir := cvdArgs.GetStringFlagValueOnSubCommandArgs("base_directory") + cvdArgs.RemoveFlagValueOnSubCommandArgs("base_directory") + if baseDir == "" { + baseDir = filepath.Join(podcvdRootDir, strconv.Itoa(os.Getuid()), attemptID) + } + podcvdBaseDir, err := filepath.Abs(baseDir) + if err != nil { + return "", fmt.Errorf("failed to resolve absolute path for base directory %q: %w", baseDir, err) + } + if err := os.MkdirAll(podcvdBaseDir, 0755); err != nil { + return "", fmt.Errorf("failed to create podcvd base dir: %w", err) + } + podcvdHomeDir := filepath.Join(podcvdBaseDir, "home") if err := os.MkdirAll(podcvdHomeDir, 0755); err != nil { return "", fmt.Errorf("failed to create podcvd home dir: %w", err) } @@ -421,14 +433,15 @@ func createAndStartContainer(ccm CuttlefishContainerManager, cvdArgs *CvdArgs) ( pathsToMount = append(pathsToMount, realPath) } } - mountSpecs := collectMountSpecs(pathsToMount, hostOut, productOut, cvdDataHome, podcvdHomeDir, cacheDir) + mountSpecs := collectMountSpecs(pathsToMount, hostOut, productOut, cvdDataHome, podcvdBaseDir, cacheDir) extraFlags := []string{ "-e", "ANDROID_HOST_OUT=/host_out", "-e", "ANDROID_PRODUCT_OUT=/product_out", - "-e", "HOME=/podcvd_home", + "-e", "HOME=/podcvd_base/home", "--label", fmt.Sprintf("%s=%s", labelCreatedBy, valueCreatedBy), "--label", fmt.Sprintf("%s=%s", labelAttemptID, attemptID), + "--label", fmt.Sprintf("%s=%s", labelBaseDir, podcvdBaseDir), "--annotation", "run.oci.keep_original_groups=1", "--cap-add", "NET_RAW", "--pids-limit", "8192", diff --git a/container/src/podcvd/internal/main.go b/container/src/podcvd/internal/main.go index 1d828eca055..22bf2aa19ae 100644 --- a/container/src/podcvd/internal/main.go +++ b/container/src/podcvd/internal/main.go @@ -98,9 +98,13 @@ func disconnectAdb(ccm CuttlefishContainerManager, groupName string) error { } func handleCreateOrStartExecution(ccm CuttlefishContainerManager, cvdArgs *CvdArgs) error { + hasConfigFile := cvdArgs.GetStringFlagValueOnSubCommandArgs("config_file") != "" + if hasConfigFile { + cvdArgs.ReplaceFlagValueOnSubCommandArgs("base_directory", "/podcvd_base") + } args := append([]string{"cvd"}, cvdArgs.SerializeCommonArgs()...) args = append(args, cvdArgs.SubCommandArgs...) - if cvdArgs.GetStringFlagValueOnSubCommandArgs("config_file") != "" { + if hasConfigFile { args = append(args, fmt.Sprintf("--override=common.group_name:%s", cvdArgs.CommonArgs.GroupName)) } @@ -124,9 +128,12 @@ func handleCreateOrStartExecution(ccm CuttlefishContainerManager, cvdArgs *CvdAr if err != nil { return fmt.Errorf("failed to inspect container: %w", err) } - attemptID := containerInfo.Config.Labels["attempt_id"] - podcvdHomeDir := filepath.Join("/var/tmp/podcvd", strconv.Itoa(os.Getuid()), attemptID) - UpdateCvdGroupJsonRaw(res, podcvdHomeDir, ip) + attemptID := containerInfo.Config.Labels[labelAttemptID] + podcvdBaseDir := containerInfo.Config.Labels[labelBaseDir] + if podcvdBaseDir == "" { + podcvdBaseDir = filepath.Join("/var/tmp/podcvd", strconv.Itoa(os.Getuid()), attemptID) + } + UpdateCvdGroupJsonRaw(res, podcvdBaseDir, ip) stdout, err := json.MarshalIndent(res, "", " ") if err != nil { return fmt.Errorf("failed to marshal json: %w", err) @@ -192,10 +199,13 @@ func handleLogsExecution(ccm CuttlefishContainerManager, cvdArgs *CvdArgs) error if err != nil { return fmt.Errorf("failed to inspect container: %w", err) } - attemptID := containerInfo.Config.Labels["attempt_id"] - podcvdHomeDir := filepath.Join("/var/tmp/podcvd", strconv.Itoa(os.Getuid()), attemptID) - regex := regexp.MustCompile(`/var/tmp/cvd/[0-9]+/[0-9]+/home`) - translatedOutput := regex.ReplaceAllString(stdoutBuf.String(), podcvdHomeDir) + attemptID := containerInfo.Config.Labels[labelAttemptID] + podcvdBaseDir := containerInfo.Config.Labels[labelBaseDir] + if podcvdBaseDir == "" { + podcvdBaseDir = filepath.Join("/var/tmp/podcvd", strconv.Itoa(os.Getuid()), attemptID) + } + regex := regexp.MustCompile(`/var/tmp/cvd/[0-9]+/[0-9]+`) + translatedOutput := regex.ReplaceAllString(stdoutBuf.String(), podcvdBaseDir) if Isatty(os.Stdout.Fd()) { translatedOutput = formatLogsList(translatedOutput) } @@ -301,11 +311,15 @@ func fleetAllCuttlefishHosts(ccm CuttlefishContainerManager) error { if err != nil { return fmt.Errorf("failed to list containers: %w", err) } - podcvdHomeDirMap := make(map[string]string) + podcvdBaseDirMap := make(map[string]string) uid := strconv.Itoa(os.Getuid()) for _, c := range containers { + podcvdBaseDir := c.Labels[labelBaseDir] + if podcvdBaseDir == "" { + podcvdBaseDir = filepath.Join("/var/tmp/podcvd", uid, c.Labels[labelAttemptID]) + } if groupName, ok := c.Labels[labelGroupName]; ok { - podcvdHomeDirMap[groupName] = filepath.Join("/var/tmp/podcvd", uid, c.Labels[labelAttemptID]) + podcvdBaseDirMap[groupName] = podcvdBaseDir } } @@ -318,7 +332,7 @@ func fleetAllCuttlefishHosts(ccm CuttlefishContainerManager) error { return err } for idx := range fleetRes.Groups { - UpdateCvdGroupJsonRaw(fleetRes.Groups[idx], podcvdHomeDirMap[res.GroupName], res.IP) + UpdateCvdGroupJsonRaw(fleetRes.Groups[idx], podcvdBaseDirMap[res.GroupName], res.IP) } combinedRes.Groups = append(combinedRes.Groups, fleetRes.Groups...) } diff --git a/container/src/podcvd/internal/parser.go b/container/src/podcvd/internal/parser.go index e22a49a2ce9..6435489d107 100644 --- a/container/src/podcvd/internal/parser.go +++ b/container/src/podcvd/internal/parser.go @@ -112,7 +112,11 @@ func (a *CvdArgs) GetStringFlagValueOnSubCommandArgs(flagName string) string { return getStringFlagValue(a.SubCommandArgs, flagName) } -func (a *CvdArgs) ReplaceFlagValueOnSubCommandArgs(flagName, newValue string) { +func (a *CvdArgs) AppendFlagValueOnSubCommandArgs(flagName, value string) { + a.SubCommandArgs = append(a.SubCommandArgs, fmt.Sprintf("-%s=%s", flagName, value)) +} + +func (a *CvdArgs) RemoveFlagValueOnSubCommandArgs(flagName string) { flags := make(map[string]struct{}) flags["-"+flagName] = struct{}{} flags["--"+flagName] = struct{}{} @@ -120,22 +124,25 @@ func (a *CvdArgs) ReplaceFlagValueOnSubCommandArgs(flagName, newValue string) { for idx, arg := range a.SubCommandArgs { if _, exists := flags[arg]; exists { if idx+1 < len(a.SubCommandArgs) && !strings.HasPrefix(a.SubCommandArgs[idx+1], "-") { - a.SubCommandArgs[idx+1] = newValue + a.SubCommandArgs = append(a.SubCommandArgs[:idx], a.SubCommandArgs[idx+2:]...) return } - a.SubCommandArgs[idx] = fmt.Sprintf("-%s=%s", flagName, newValue) + a.SubCommandArgs = append(a.SubCommandArgs[:idx], a.SubCommandArgs[idx+1:]...) return } splitArg := strings.SplitN(arg, "=", 2) if len(splitArg) == 2 { if _, exists := flags[splitArg[0]]; exists { - a.SubCommandArgs[idx] = fmt.Sprintf("%s=%s", splitArg[0], newValue) + a.SubCommandArgs = append(a.SubCommandArgs[:idx], a.SubCommandArgs[idx+1:]...) return } } } +} - a.SubCommandArgs = append(a.SubCommandArgs, fmt.Sprintf("-%s=%s", flagName, newValue)) +func (a *CvdArgs) ReplaceFlagValueOnSubCommandArgs(flagName, newValue string) { + a.RemoveFlagValueOnSubCommandArgs(flagName) + a.AppendFlagValueOnSubCommandArgs(flagName, newValue) } func mapSubcommand(subcmd string) string { diff --git a/e2etests/cvd/logs_tests/BUILD.bazel b/e2etests/cvd/logs_tests/BUILD.bazel index 852ff4a52b4..880b0135d42 100644 --- a/e2etests/cvd/logs_tests/BUILD.bazel +++ b/e2etests/cvd/logs_tests/BUILD.bazel @@ -10,7 +10,6 @@ go_test( "exclusive", "external", "no-sandbox", - "podcvd_excluded", "requires_ab", "supports-graceful-termination", ],