blob: 64e4011cd2282bdc52ac1fb3f387497f659968d0 [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package cli
import (
"errors"
"flag"
"fmt"
"strings"
"go.chromium.org/chromiumos/test/provision/v2/android-provision/common"
"go.chromium.org/chromiumos/test/provision/v2/android-provision/executor"
common_utils "go.chromium.org/chromiumos/test/provision/v2/common-utils"
"go.chromium.org/chromiumos/test/provision/v2/common-utils/metadata"
"go.chromium.org/chromiumos/test/provision/v2/common-utils/server"
"go.chromium.org/chromiumos/config/go/test/api"
)
// ServerCommand executed the provisioning as a Server
type ServerCommand struct {
metadata *metadata.ServerMetadata
logFileName string
metadataFile string
flagSet *flag.FlagSet
}
func NewServerCommand() *ServerCommand {
sc := &ServerCommand{
flagSet: flag.NewFlagSet("server", flag.ContinueOnError),
metadata: &metadata.ServerMetadata{},
}
sc.flagSet.IntVar(&sc.metadata.Port, "port", common.DefaultServerPort, fmt.Sprintf("Specify the port for the server. Default value %d.", common.DefaultServerPort))
sc.flagSet.StringVar(&sc.logFileName, "log-path", common.DefaultLogDirectory, fmt.Sprintf("Path to record execution logs. Default value is %s", common.DefaultLogDirectory))
sc.flagSet.StringVar(&sc.metadataFile, "metadata", "", "Specify the request jsonproto input file. Provide service paths and ProvisionState.")
return sc
}
func (sc *ServerCommand) Is(group string) bool {
return strings.HasPrefix(group, "s")
}
func (sc *ServerCommand) Name() string {
return "server"
}
func (sc *ServerCommand) Init(args []string) error {
err := sc.flagSet.Parse(args)
if err != nil {
return err
}
sc.metadata.Log, err = common.SetUpLog(sc.logFileName)
if err != nil {
return fmt.Errorf("unable to set up logs: %s", err)
}
if err = sc.validateCLIInputs(); err != nil {
return err
}
if sc.metadataFile != "" {
sc.metadata.Log.Println("warning: CLI arg 'metadata' is deprecated, please use the StartUp RPC instead.")
apr, err := common_utils.ParseAndroidProvisionRequest(sc.metadataFile)
if err != nil {
return fmt.Errorf("unable to parse AndroidProvisionRequest proto: %s", err)
}
if err = sc.validateProtoInputs(apr); err != nil {
return err
}
sc.metadata.Dut = apr.GetDut()
sc.metadata.DutAddress = fmt.Sprintf("%s:%d", apr.GetDutServer().GetAddress(), apr.GetDutServer().GetPort())
}
return nil
}
func (sc *ServerCommand) Usage() {
sc.flagSet.Usage()
}
// validateCLIInputs ensures the CLI input values are valid
func (sc *ServerCommand) validateCLIInputs() error {
return nil
}
// validateProtoInputs ensures the proto part of the CLI input is valid
func (sc *ServerCommand) validateProtoInputs(apr *api.AndroidProvisionRequest) error {
if apr.GetDut() == nil || apr.GetDut().GetId().GetValue() == "" {
return errors.New("dut id is not specified in input file")
}
if apr.GetDut().GetAndroid() == nil {
return errors.New("android dut is not specified in input file")
}
if apr.GetDut().GetAndroid().GetSerialNumber() == "" {
return errors.New("android dut serial number is missing from input file")
}
if apr.GetDut().GetAndroid().GetAssociatedHostname() == nil || apr.GetDut().GetAndroid().GetAssociatedHostname().GetAddress() == "" {
return errors.New("associated host of android dut is not specified in input file")
}
if apr.GetDutServer() == nil || apr.DutServer.GetAddress() == "" || apr.DutServer.GetPort() <= 0 {
return errors.New("dut server address is no specified or incorrect in input file")
}
return nil
}
func (sc *ServerCommand) Run() error {
sc.metadata.Log.Printf("running server mode:")
svc, closer, err := server.NewProvisionServer(sc.metadata, &executor.AndroidProvisionExecutor{})
defer closer()
if err != nil {
sc.metadata.Log.Fatalln("failed to create provision: ", err)
return err
}
if err := svc.Start(); err != nil {
sc.metadata.Log.Fatalln("failed server execution: ", err)
return err
}
return nil
}