blob: 68c3ab3210524a0066697ddccad60bc5de5ea9c3 [file] [log] [blame] [edit]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package autoupdate
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"github.com/golang/protobuf/ptypes/empty"
"google.golang.org/grpc"
"chromiumos/tast/common/testexec"
"chromiumos/tast/errors"
"chromiumos/tast/lsbrelease"
aupb "chromiumos/tast/services/cros/autoupdate"
"chromiumos/tast/testing"
)
func init() {
testing.AddService(&testing.Service{
Register: func(srv *grpc.Server, s *testing.ServiceState) {
aupb.RegisterUpdateServiceServer(srv, &UpdateService{s: s})
},
})
}
// UpdateService implements tast.cros.autoupdate.UpdateService.
type UpdateService struct { // NOLINT
s *testing.ServiceState
}
const statefulPath = "/mnt/stateful_partition/etc/lsb-release"
// CheckForUpdate starts update_engine_client to update the OS.
func (u *UpdateService) CheckForUpdate(ctx context.Context, req *aupb.UpdateRequest) (*empty.Empty, error) {
// Collect the arguments.
args := []string{"--update"}
if req.OmahaUrl != "" {
testing.ContextLog(ctx, "Adding Omaha URL to arguments")
args = append(args, fmt.Sprintf("--omaha_url=%s", req.OmahaUrl))
}
if req.AppVersion != "" {
testing.ContextLog(ctx, "Adding app version to arguments")
args = append(args, fmt.Sprintf("--app_version=%s", req.AppVersion))
}
cmd := testexec.CommandContext(ctx, "update_engine_client", args...)
testing.ContextLog(ctx, "Starting the update")
_, err := cmd.Output(testexec.DumpLogOnError)
if err != nil {
return &empty.Empty{}, errors.Wrap(err, "failed to start update engine client")
}
return &empty.Empty{}, nil
}
// LSBReleaseContent gets the content of /etc/lsb-release.
func (u *UpdateService) LSBReleaseContent(ctx context.Context, req *empty.Empty) (*aupb.LSBRelease, error) {
content, err := lsbrelease.Load()
if err != nil {
return &aupb.LSBRelease{}, errors.Wrap(err, "failed to load lsbrelease information from /etc/lsb-release")
}
contentJSON, err := json.Marshal(content)
if err != nil {
return &aupb.LSBRelease{}, errors.Wrap(err, "failed to serialize the content of /etc/lsb-release")
}
return &aupb.LSBRelease{ContentJson: contentJSON}, nil
}
// StatefulLSBReleaseContent gets the content of /mnt/stateful_partition/etc/lsb-release.
// The values in this file overwrite the effect of the ones in /etc/lsb-release.
func (u *UpdateService) StatefulLSBReleaseContent(ctx context.Context, req *empty.Empty) (*aupb.LSBRelease, error) {
content, err := lsbrelease.LoadFrom(statefulPath)
if err != nil {
return &aupb.LSBRelease{}, errors.Wrapf(err, "failed to retreive lsbrelease information from %s", statefulPath)
}
contentJSON, err := json.Marshal(content)
if err != nil {
return &aupb.LSBRelease{}, errors.Wrapf(err, "failed to serialize the content of %s", statefulPath)
}
return &aupb.LSBRelease{ContentJson: contentJSON}, nil
}
// OverwriteStatefulLSBRelease overwrites the content of /mnt/stateful_partition/etc/lsb-release.
func (u *UpdateService) OverwriteStatefulLSBRelease(ctx context.Context, req *aupb.LSBRelease) (*empty.Empty, error) {
var content map[string]string
if err := json.Unmarshal(req.ContentJson, &content); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal the request content")
}
output := new(bytes.Buffer)
for key, value := range content {
fmt.Fprintf(output, "%s=%s\n", key, value)
}
err := ioutil.WriteFile(statefulPath, output.Bytes(), 0644)
if err != nil {
return &empty.Empty{}, errors.Wrapf(err, "failed to write the new content to %s", statefulPath)
}
return &empty.Empty{}, nil
}