blob: 12847389b82d9a5df8448372a04447a53947945b [file] [edit]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package deviceconfig
import (
"context"
"fmt"
"strings"
"time"
"cloud.google.com/go/storage"
"github.com/golang/protobuf/proto"
"github.com/google/go-cmp/cmp"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/testing/protocmp"
"go.chromium.org/chromiumos/infra/proto/go/device"
"go.chromium.org/luci/common/logging"
inv "go.chromium.org/infra/cros/lab_inventory/protos"
)
func compareBoxsterWithV0(ctx context.Context, boxsterCfgs, v0Cfgs []*device.Config) error {
writer, err := getCloudStorageWriter(ctx, "cros-lab-inventory-dev.appspot.com", fmt.Sprintf("device_config_diff/%s.log", getDiffFilename()))
if err != nil {
return err
}
defer func() {
if writer != nil {
if err := writer.Close(); err != nil {
logging.Warningf(ctx, "failed to close cloud storage writer: %s", err)
}
}
}()
logging.Debugf(ctx, "start comparing device configs from boxster & V0")
v0CfgMap := make(map[string]*device.Config)
boxsterCfgMap := make(map[string]*device.Config)
for _, c := range v0Cfgs {
v0CfgMap[GetDeviceConfigIDStr(c.GetId())] = c
}
for _, c := range boxsterCfgs {
boxsterCfgMap[GetDeviceConfigIDStr(c.GetId())] = c
}
count := 0
var diff []string
var logs []string
for _, c := range boxsterCfgs {
idStr := GetDeviceConfigIDStr(c.GetId())
if found, ok := v0CfgMap[idStr]; ok {
// device.Config is not in type protoreflect.ProtoMessage as it's not generated via cproto.
// Convert device.Config to inv.Config
newFound := copyDeviceConfig(found)
newC := copyDeviceConfig(c)
if !proto.Equal(found, c) {
diff = append(diff, fmt.Sprintf("ID: %s", idStr))
names := []protoreflect.Name{
protoreflect.Name("ee"),
protoreflect.Name("tam"),
protoreflect.Name("soc_email_group"),
protoreflect.Name("odm_email_group"),
protoreflect.Name("oem_email_group"),
protoreflect.Name("oem"),
protoreflect.Name("odm"),
protoreflect.Name("id"),
protoreflect.Name("firmware_configuration"),
}
opt1 := protocmp.IgnoreFields(newFound, names...)
diff = append(diff, cmp.Diff(newFound, newC, protocmp.Transform(), opt1))
count++
}
}
}
logs = append(logs, fmt.Sprintf("######## %d different device configs ############", count))
logs = append(logs, diff...)
logs = append(logs, "\n\n######## device config ID only exists in boxster ############")
for _, c := range boxsterCfgs {
idStr := GetDeviceConfigIDStr(c.GetId())
if _, ok := v0CfgMap[idStr]; !ok {
logs = append(logs, idStr)
}
}
logs = append(logs, "\n\n######## device config ID only exists in device config V0 ############")
for _, c := range v0Cfgs {
idStr := GetDeviceConfigIDStr(c.GetId())
if _, ok := boxsterCfgMap[idStr]; !ok {
logs = append(logs, idStr)
}
}
if _, err := fmt.Fprint(writer, strings.Join(logs, "\n")); err != nil {
return err
}
return nil
}
func getDiffFilename() string {
loc, err := time.LoadLocation("America/Los_Angeles")
if err == nil {
return time.Now().UTC().In(loc).Format("2006-01-02T03:04:05")
}
return time.Now().UTC().Format("2006-01-02T03:04:05")
}
func getCloudStorageWriter(ctx context.Context, bucketName, filename string) (*storage.Writer, error) {
storageClient, err := storage.NewClient(ctx)
if err != nil {
logging.Warningf(ctx, "failed to create cloud storage client")
return nil, err
}
bucket := storageClient.Bucket(bucketName)
logging.Infof(ctx, "all diff will be saved to https://storage.cloud.google.com/%s/%s", bucketName, filename)
return bucket.Object(filename).NewWriter(ctx), nil
}
func copyDeviceConfig(old *device.Config) *inv.Config {
if old == nil {
return nil
}
s := proto.MarshalTextString(old)
var newDC inv.Config
proto.UnmarshalText(s, &newDC)
return &newDC
}