blob: 78f9bbf90cdb1cdd06e1356493f98cb6b4b6918c [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 commands
import (
common_utils "go.chromium.org/chromiumos/test/provision/v2/common-utils"
"go.chromium.org/chromiumos/test/provision/v2/cros-provision/service"
"context"
"fmt"
"log"
"path"
conf "go.chromium.org/chromiumos/config/go"
"go.chromium.org/chromiumos/config/go/test/api"
)
type InstallDLCsCommand struct {
ctx context.Context
cs *service.CrOSService
}
func NewInstallDLCsCommand(ctx context.Context, cs *service.CrOSService) *InstallDLCsCommand {
return &InstallDLCsCommand{
ctx: ctx,
cs: cs,
}
}
func (c *InstallDLCsCommand) Execute(log *log.Logger) error {
log.Printf("Start InstallDLCsCommand Execute")
activeSlot := common_utils.ActiveDlcMap[c.cs.MachineMetadata.RootInfo.RootPartNum]
var err error
errCh := make(chan error)
for _, spec := range c.cs.DlcSpecs {
go func(spec *api.CrOSProvisionMetadata_DLCSpec) {
errCh <- c.installDLC(c.ctx, spec, activeSlot)
}(spec)
}
log.Printf("InstallDLCsCommand installDLC completed")
for range c.cs.DlcSpecs {
errTmp := <-errCh
if errTmp == nil {
continue
}
err = fmt.Errorf("%s, %s", err, errTmp)
}
log.Printf("InstallDLCsCommand Success")
return err
}
func (c *InstallDLCsCommand) Revert() error {
return nil
}
// installDLC installs all relevant DLCs
func (c *InstallDLCsCommand) installDLC(ctx context.Context, spec *api.CrOSProvisionMetadata_DLCSpec, slot string) error {
dlcID := spec.GetId()
dlcOutputDir := path.Join(common_utils.DlcCacheDir, dlcID, common_utils.DlcPackage)
verified, err := c.isDLCVerified(ctx, spec.GetId(), slot)
if err != nil {
return fmt.Errorf("failed is DLC verified check, %s", err)
}
// Skip installing the DLC if already verified.
if verified {
log.Printf("provision DLC %s skipped as already verified", dlcID)
return nil
}
if c.cs.ImagePath.HostType == conf.StoragePath_LOCAL || c.cs.ImagePath.HostType == conf.StoragePath_HOSTTYPE_UNSPECIFIED {
return fmt.Errorf("only GS copying is implemented")
}
dlcURL := path.Join(c.cs.ImagePath.GetPath(), "dlc", dlcID, common_utils.DlcPackage, common_utils.DlcImage)
dlcOutputSlotDir := path.Join(dlcOutputDir, string(slot))
dlcOutputImage := path.Join(dlcOutputSlotDir, common_utils.DlcImage)
if err := c.cs.Connection.CreateDirectories(ctx, []string{dlcOutputSlotDir}); err != nil {
return fmt.Errorf("failed to create DLC directories %s, %s", dlcID, err)
}
if err := c.cs.Connection.CopyData(ctx, dlcURL, dlcOutputImage); err != nil {
return fmt.Errorf("failed to download DLCs, %s", err)
}
return nil
}
// isDLCVerified checks if the desired DLC already exists within the system
func (c *InstallDLCsCommand) isDLCVerified(ctx context.Context, dlcID, slot string) (bool, error) {
verified, err := c.cs.Connection.PathExists(ctx, path.Join(common_utils.DlcLibDir, dlcID, slot, common_utils.DlcVerified))
if err != nil {
return false, fmt.Errorf("failed to check if DLC %s is verified, %s", dlcID, err)
}
return verified, nil
}
func (c *InstallDLCsCommand) GetErrorMessage() string {
return "failed to install DLCs"
}
func (c *InstallDLCsCommand) GetStatus() api.InstallResponse_Status {
return api.InstallResponse_STATUS_INSTALL_DLC_FAILED
}