Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions container/debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@

GOBIN := $$(which go || echo /usr/lib/$$(ls /usr/lib | grep "^go-1." | sort -V | tail -1)/bin/go)
PODCVD_SOURCE_DIR := src/podcvd
PODCVD_BIN_DIR := ./cmd/podcvd

%:
dh $@ --with=config-package

.PHONY: override_dh_auto_build
override_dh_auto_build:
(cd ${PODCVD_SOURCE_DIR} && $(GOBIN) build -v -buildmode=pie -ldflags="-w")
(cd ${PODCVD_SOURCE_DIR} && $(GOBIN) build -v -buildmode=pie -ldflags="-w" ${PODCVD_BIN_DIR})

.PHONY: override_dh_auto_test
override_dh_auto_test:
(cd ${PODCVD_SOURCE_DIR} && $(GOBIN) test)
(cd ${PODCVD_SOURCE_DIR} && $(GOBIN) test ./...)
dh_auto_test

.PHONY: override_dh_installinit
Expand Down
2 changes: 1 addition & 1 deletion container/src/podcvd/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ execute `cvd help` or `cvd create` after installing `cuttlefish-base`.

### Manually build podcvd binary

Execute `go build` from `container/src/podcvd` directory.
Execute `go build ./cmd/podcvd` from `container/src/podcvd` directory.

### Manually build cuttlefish-podcvd debian package

Expand Down
25 changes: 25 additions & 0 deletions container/src/podcvd/cmd/podcvd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (C) 2026 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"os"

"github.com/google/android-cuttlefish/container/src/podcvd/internal"
)

func main() {
internal.Main(os.Args[1:])
}
157 changes: 78 additions & 79 deletions container/src/podcvd/main.go → container/src/podcvd/internal/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package main
package internal

import (
"context"
Expand All @@ -24,31 +24,89 @@ import (
"sync"

"github.com/google/android-cuttlefish/container/src/libcfcontainer"
"github.com/google/android-cuttlefish/container/src/podcvd/internal"
)

func Main(args []string) {
cvdArgs := ParseCvdArgs(args)
if len(cvdArgs.SubCommandArgs) == 0 {
cvdArgs.SubCommandArgs = []string{"help"}
}

ccm, err := CuttlefishContainerManager()
if err != nil {
log.Fatal(err)
}

subcommand := cvdArgs.SubCommandArgs[0]
if cvdArgs.HasHelpFlagOnSubCommandArgs() {
switch subcommand {
case "cache", "clear", "create", "display", "env", "fetch", "fleet", "help", "lint", "load", "login", "powerbtn", "powerwash", "remove", "reset", "restart", "resume", "screen_recording", "snapshot_take", "status", "stop", "suspend", "version":
cvdArgs.SubCommandArgs = []string{subcommand, "--help"}
if err := handleToolingSubcommands(ccm, cvdArgs); err != nil {
log.Fatal(err)
}
case "bugreport", "start":
// TODO(seungjaeyoo): Support help flag for other subcommands of cvd as well.
log.Fatalf("help flag support for subcommand %q is not implemented yet", subcommand)
default:
log.Fatalf("unknown subcommand %q", subcommand)
}
} else {
if err := CheckDeviceAccessible(); err != nil {
log.Fatal(err)
}
switch subcommand {
case "bugreport", "create", "display", "env", "powerbtn", "powerwash", "remove", "restart", "resume", "screen_recording", "snapshot_take", "start", "status", "stop", "suspend":
if err := handleSubcommandsForSingleInstanceGroup(ccm, cvdArgs); err != nil {
log.Fatal(err)
}
case "clear", "reset":
if err := clearAllCuttlefishHosts(ccm); err != nil {
log.Fatal(err)
}
case "fleet":
if err := fleetAllCuttlefishHosts(ccm); err != nil {
log.Fatal(err)
}
case "help", "login", "version":
if err := handleToolingSubcommands(ccm, cvdArgs); err != nil {
log.Fatal(err)
}
case "fetch":
if err := ExecFetchCmdOnDisposableHost(ccm, cvdArgs); err != nil {
log.Fatal(err)
}
case "cache", "lint":
// TODO(seungjaeyoo): Support other subcommands of cvd as well.
log.Fatalf("subcommand %q is not implemented yet", subcommand)
default:
log.Fatalf("unknown subcommand %q", subcommand)
}
}
}

func disconnectAdb(ccm libcfcontainer.CuttlefishContainerManager, groupName string) error {
stdout, err := ccm.ExecOnContainer(context.Background(), internal.ContainerName(groupName), false, []string{"cvd", "fleet"})
stdout, err := ccm.ExecOnContainer(context.Background(), ContainerName(groupName), false, []string{"cvd", "fleet"})
if err != nil {
return err
}
instanceGroup, err := internal.ParseInstanceGroups(stdout, groupName)
instanceGroup, err := ParseInstanceGroups(stdout, groupName)
if err != nil {
return err
}
return internal.DisconnectAdb(ccm, *instanceGroup)
return DisconnectAdb(ccm, *instanceGroup)
}

func handleSubcommandsForSingleInstanceGroup(ccm libcfcontainer.CuttlefishContainerManager, cvdArgs *internal.CvdArgs) error {
func handleSubcommandsForSingleInstanceGroup(ccm libcfcontainer.CuttlefishContainerManager, cvdArgs *CvdArgs) error {
subcommand := cvdArgs.SubCommandArgs[0]
switch subcommand {
case "create":
if err := internal.CreateCuttlefishHost(ccm, cvdArgs.CommonArgs); err != nil {
if err := CreateCuttlefishHost(ccm, cvdArgs.CommonArgs); err != nil {
return err
}
default:
if cvdArgs.CommonArgs.GroupName == "" {
groupNameIpAddrMap, err := internal.Ipv4AddressesByGroupNames(ccm)
groupNameIpAddrMap, err := Ipv4AddressesByGroupNames(ccm)
if err != nil {
return fmt.Errorf("failed to get IPv4 addresses for group names: %w", err)
}
Expand All @@ -70,30 +128,30 @@ func handleSubcommandsForSingleInstanceGroup(ccm libcfcontainer.CuttlefishContai
// If the subcommand is 'remove', it doesn't need to execute cvd on the
// container instance as it should be removed in the end.
if subcommand == "remove" {
return internal.DeleteCuttlefishHost(ccm, cvdArgs.CommonArgs.GroupName)
return DeleteCuttlefishHost(ccm, cvdArgs.CommonArgs.GroupName)
}
}
args := append([]string{"cvd"}, cvdArgs.SerializeCommonArgs()...)
args = append(args, cvdArgs.SubCommandArgs...)
stdout, err := ccm.ExecOnContainer(context.Background(), internal.ContainerName(cvdArgs.CommonArgs.GroupName), true, args)
stdout, err := ccm.ExecOnContainer(context.Background(), ContainerName(cvdArgs.CommonArgs.GroupName), true, args)
if err != nil {
return err
}
switch subcommand {
case "create", "start":
instanceGroup, err := internal.ParseInstanceGroup(stdout, cvdArgs.CommonArgs.GroupName)
instanceGroup, err := ParseInstanceGroup(stdout, cvdArgs.CommonArgs.GroupName)
if err != nil {
return err
}
if err := internal.ConnectAdb(ccm, *instanceGroup); err != nil {
if err := ConnectAdb(ccm, *instanceGroup); err != nil {
return err
}
}
return nil
}

func clearAllCuttlefishHosts(ccm libcfcontainer.CuttlefishContainerManager) error {
groupNameIpAddrMap, err := internal.Ipv4AddressesByGroupNames(ccm)
groupNameIpAddrMap, err := Ipv4AddressesByGroupNames(ccm)
if err != nil {
return fmt.Errorf("failed to get IPv4 addresses for group names: %w", err)
}
Expand All @@ -107,12 +165,12 @@ func clearAllCuttlefishHosts(ccm libcfcontainer.CuttlefishContainerManager) erro
errCh <- err
return
}
errCh <- internal.DeleteCuttlefishHost(ccm, groupName)
errCh <- DeleteCuttlefishHost(ccm, groupName)
}()
}
go func() {
defer wg.Done()
errCh <- internal.DeleteToolingHost(ccm)
errCh <- DeleteToolingHost(ccm)
}()
wg.Wait()
close(errCh)
Expand All @@ -128,7 +186,7 @@ func fleetAllCuttlefishHosts(ccm libcfcontainer.CuttlefishContainerManager) erro
Groups []json.RawMessage `json:"groups"`
}

groupNameIpAddrMap, err := internal.Ipv4AddressesByGroupNames(ccm)
groupNameIpAddrMap, err := Ipv4AddressesByGroupNames(ccm)
if err != nil {
return fmt.Errorf("failed to get IPv4 addresses for group names: %w", err)
}
Expand All @@ -139,7 +197,7 @@ func fleetAllCuttlefishHosts(ccm libcfcontainer.CuttlefishContainerManager) erro
for groupName := range groupNameIpAddrMap {
go func() {
defer wg.Done()
stdout, err := ccm.ExecOnContainer(context.Background(), internal.ContainerName(groupName), false, []string{"cvd", "fleet"})
stdout, err := ccm.ExecOnContainer(context.Background(), ContainerName(groupName), false, []string{"cvd", "fleet"})
if err != nil {
errCh <- err
return
Expand Down Expand Up @@ -172,73 +230,14 @@ func fleetAllCuttlefishHosts(ccm libcfcontainer.CuttlefishContainerManager) erro
return nil
}

func handleToolingSubcommands(ccm libcfcontainer.CuttlefishContainerManager, cvdArgs *internal.CvdArgs) error {
if err := internal.CreateToolingHost(ccm); err != nil {
func handleToolingSubcommands(ccm libcfcontainer.CuttlefishContainerManager, cvdArgs *CvdArgs) error {
if err := CreateToolingHost(ccm); err != nil {
return err
}
args := append([]string{"cvd"}, cvdArgs.SerializeCommonArgs()...)
args = append(args, cvdArgs.SubCommandArgs...)
if _, err := ccm.ExecOnContainer(context.Background(), internal.ToolingContainerName, true, args); err != nil {
if _, err := ccm.ExecOnContainer(context.Background(), ToolingContainerName, true, args); err != nil {
return err
}
return nil
}

func main() {
cvdArgs := internal.ParseCvdArgs(os.Args[1:])
if len(cvdArgs.SubCommandArgs) == 0 {
cvdArgs.SubCommandArgs = []string{"help"}
}

ccm, err := internal.CuttlefishContainerManager()
if err != nil {
log.Fatal(err)
}

subcommand := cvdArgs.SubCommandArgs[0]
if cvdArgs.HasHelpFlagOnSubCommandArgs() {
switch subcommand {
case "cache", "clear", "create", "display", "env", "fetch", "fleet", "help", "lint", "load", "login", "powerbtn", "powerwash", "remove", "reset", "restart", "resume", "screen_recording", "snapshot_take", "status", "stop", "suspend", "version":
cvdArgs.SubCommandArgs = []string{subcommand, "--help"}
if err := handleToolingSubcommands(ccm, cvdArgs); err != nil {
log.Fatal(err)
}
case "bugreport", "start":
// TODO(seungjaeyoo): Support help flag for other subcommands of cvd as well.
log.Fatalf("help flag support for subcommand %q is not implemented yet", subcommand)
default:
log.Fatalf("unknown subcommand %q", subcommand)
}
} else {
if err := internal.CheckDeviceAccessible(); err != nil {
log.Fatal(err)
}
switch subcommand {
case "bugreport", "create", "display", "env", "powerbtn", "powerwash", "remove", "restart", "resume", "screen_recording", "snapshot_take", "start", "status", "stop", "suspend":
if err := handleSubcommandsForSingleInstanceGroup(ccm, cvdArgs); err != nil {
log.Fatal(err)
}
case "clear", "reset":
if err := clearAllCuttlefishHosts(ccm); err != nil {
log.Fatal(err)
}
case "fleet":
if err := fleetAllCuttlefishHosts(ccm); err != nil {
log.Fatal(err)
}
case "help", "login", "version":
if err := handleToolingSubcommands(ccm, cvdArgs); err != nil {
log.Fatal(err)
}
case "fetch":
if err := internal.ExecFetchCmdOnDisposableHost(ccm, cvdArgs); err != nil {
log.Fatal(err)
}
case "cache", "lint":
// TODO(seungjaeyoo): Support other subcommands of cvd as well.
log.Fatalf("subcommand %q is not implemented yet", subcommand)
default:
log.Fatalf("unknown subcommand %q", subcommand)
}
}
}
Loading