Justin Suen | f9095ee | 2021-06-25 18:25:44 +0000 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # -*- coding: utf-8 -*- |
| 3 | |
| 4 | # Copyright 2021 The Chromium OS Authors. All rights reserved. |
| 5 | # Use of this source code is governed by a BSD-style license that can be |
| 6 | # found in the LICENSE file. |
Justin Suen | 84529bd | 2021-07-22 18:06:48 +0000 | [diff] [blame] | 7 | """Marshal ConfigBundles and DutAttributes. Store them into the UFS datastore |
| 8 | through the Google datastore API. |
Justin Suen | f9095ee | 2021-06-25 18:25:44 +0000 | [diff] [blame] | 9 | |
Justin Suen | 84529bd | 2021-07-22 18:06:48 +0000 | [diff] [blame] | 10 | By default, this script converts a few config-related protos into datastore |
| 11 | entities: |
| 12 | |
| 13 | 1. ConfigBundleList from 'hw_design/generated/configs.jsonproto' |
| 14 | 2. DutAttributeList from 'dut_attributes/generated/dut_attributes.jsonproto' |
Justin Suen | 5aaa7cd | 2021-09-01 08:55:53 +0000 | [diff] [blame^] | 15 | 3. FlatConfigList from 'hw_design/generated/flattened.jsonproto' |
Justin Suen | 84529bd | 2021-07-22 18:06:48 +0000 | [diff] [blame] | 16 | |
| 17 | The lists are parsed and individual entities are extracted. Using the datastore |
| 18 | client specified, it encodes the protos as datastore entities and stores them |
| 19 | into the UFS datastore. |
Justin Suen | f9095ee | 2021-06-25 18:25:44 +0000 | [diff] [blame] | 20 | """ |
| 21 | |
| 22 | import argparse |
| 23 | import datetime |
| 24 | import logging |
| 25 | |
| 26 | from google.cloud import datastore |
| 27 | |
| 28 | from checker import io_utils |
| 29 | from common import proto_utils |
| 30 | |
| 31 | # type constants |
Justin Suen | 84529bd | 2021-07-22 18:06:48 +0000 | [diff] [blame] | 32 | CB_INPUT_TYPE = 'chromiumos.config.payload.ConfigBundleList' |
| 33 | CB_OUTPUT_TYPE = 'chromiumos.config.payload.ConfigBundle' |
| 34 | DA_INPUT_TYPE = 'chromiumos.test.api.DutAttributeList' |
| 35 | DA_OUTPUT_TYPE = 'chromiumos.test.api.DutAttribute' |
Justin Suen | 5aaa7cd | 2021-09-01 08:55:53 +0000 | [diff] [blame^] | 36 | FC_INPUT_TYPE = 'chromiumos.config.payload.FlatConfigList' |
| 37 | FC_OUTPUT_TYPE = 'chromiumos.config.payload.FlatConfig' |
Justin Suen | f9095ee | 2021-06-25 18:25:44 +0000 | [diff] [blame] | 38 | |
| 39 | # UFS services |
| 40 | UFS_DEV_PROJECT = 'unified-fleet-system-dev' |
| 41 | UFS_PROD_PROJECT = 'unified-fleet-system' |
| 42 | |
| 43 | # datastore constants |
| 44 | CONFIG_BUNDLE_KIND = 'ConfigBundle' |
Justin Suen | 84529bd | 2021-07-22 18:06:48 +0000 | [diff] [blame] | 45 | DUT_ATTRIBUTE_KIND = 'DutAttribute' |
Justin Suen | 5aaa7cd | 2021-09-01 08:55:53 +0000 | [diff] [blame^] | 46 | FLAT_CONFIG_KIND = 'FlatConfig' |
Justin Suen | f9095ee | 2021-06-25 18:25:44 +0000 | [diff] [blame] | 47 | |
| 48 | |
| 49 | def get_ufs_project(env): |
| 50 | """Return project name based on env argument.""" |
| 51 | if env == 'dev': |
| 52 | return UFS_DEV_PROJECT |
| 53 | if env == 'prod': |
| 54 | return UFS_PROD_PROJECT |
| 55 | raise RuntimeError('get_ufs_project: environment %s not supported' % env) |
| 56 | |
| 57 | |
Justin Suen | 5aaa7cd | 2021-09-01 08:55:53 +0000 | [diff] [blame^] | 58 | def generate_config_bundle_id(bundle): |
Justin Suen | f9095ee | 2021-06-25 18:25:44 +0000 | [diff] [blame] | 59 | """Generate ConfigBundleEntity id as ${program_id}-${design_id}.""" |
| 60 | return bundle.design_list[0].program_id.value + '-' + bundle.design_list[ |
| 61 | 0].id.value |
| 62 | |
| 63 | |
Justin Suen | 84529bd | 2021-07-22 18:06:48 +0000 | [diff] [blame] | 64 | def handle_config_bundle_list(cb_list_path, env): |
| 65 | """Take a path to a ConfigBundleList, iterate through the list and store into |
| 66 | UFS datastore based on env. |
| 67 | """ |
| 68 | cb_list = io_utils.read_json_proto( |
| 69 | protodb.GetSymbol(CB_INPUT_TYPE)(), cb_list_path) |
| 70 | |
| 71 | for config_bundle in cb_list.values: |
Justin Suen | 5aaa7cd | 2021-09-01 08:55:53 +0000 | [diff] [blame^] | 72 | update_config(config_bundle, get_ufs_project(env), flat=False) |
Justin Suen | 84529bd | 2021-07-22 18:06:48 +0000 | [diff] [blame] | 73 | |
| 74 | |
Justin Suen | 5aaa7cd | 2021-09-01 08:55:53 +0000 | [diff] [blame^] | 75 | def generate_flat_config_id(bundle): |
| 76 | """Generate FlatConfigEntity id as ${program_id}-${design_id}-${design_config_id} |
| 77 | if design_config_id is available. Else ${program_id}-${design_id}.""" |
| 78 | if bundle.hw_design_config.id.value: |
| 79 | return bundle.hw_design.program_id.value + '-' + bundle.hw_design.id.value \ |
| 80 | + '-' + bundle.hw_design_config.id.value |
| 81 | return bundle.hw_design.program_id.value + '-' + bundle.hw_design.id.value |
| 82 | |
| 83 | |
| 84 | def handle_flat_config_list(fc_list_path, env): |
| 85 | """Take a path to a FlatConfigList, iterate through the list and store into |
| 86 | UFS datastore based on env. |
| 87 | """ |
| 88 | fc_list = io_utils.read_json_proto( |
| 89 | protodb.GetSymbol(FC_INPUT_TYPE)(), fc_list_path) |
| 90 | |
| 91 | for flat_config in fc_list.values: |
| 92 | update_config(flat_config, get_ufs_project(env), flat=True) |
| 93 | |
| 94 | |
| 95 | def update_config(config, project, flat=False): |
| 96 | """Take a ConfigBundle or FlatConfig and store it an an entity in the UFS datastore.""" |
| 97 | if flat: |
| 98 | kind = FLAT_CONFIG_KIND |
| 99 | eid = generate_flat_config_id(config) |
| 100 | else: |
| 101 | kind = CONFIG_BUNDLE_KIND |
| 102 | eid = generate_config_bundle_id(config) |
| 103 | logging.info('update_config: handling %s', eid) |
Justin Suen | f9095ee | 2021-06-25 18:25:44 +0000 | [diff] [blame] | 104 | |
| 105 | client = datastore.Client(project=project,) |
Justin Suen | 5aaa7cd | 2021-09-01 08:55:53 +0000 | [diff] [blame^] | 106 | key = client.key(kind, eid) |
Justin Suen | f9095ee | 2021-06-25 18:25:44 +0000 | [diff] [blame] | 107 | entity = datastore.Entity( |
| 108 | key=key, |
| 109 | exclude_from_indexes=['ConfigData'], |
| 110 | ) |
Justin Suen | 5aaa7cd | 2021-09-01 08:55:53 +0000 | [diff] [blame^] | 111 | entity['ConfigData'] = config.SerializeToString() |
Justin Suen | f9095ee | 2021-06-25 18:25:44 +0000 | [diff] [blame] | 112 | entity['updated'] = datetime.datetime.now() |
| 113 | |
Justin Suen | 5aaa7cd | 2021-09-01 08:55:53 +0000 | [diff] [blame^] | 114 | logging.info('update_config: putting entity into datastore for %s', eid) |
Justin Suen | 84529bd | 2021-07-22 18:06:48 +0000 | [diff] [blame] | 115 | client.put(entity) |
| 116 | |
| 117 | |
| 118 | def handle_dut_attribute_list(dut_attr_list_path, env): |
| 119 | """Take a path to a DutAttributeList, iterate through the list and store into |
| 120 | UFS datastore based on env. |
| 121 | """ |
| 122 | dut_attr_list = io_utils.read_json_proto( |
| 123 | protodb.GetSymbol(DA_INPUT_TYPE)(), dut_attr_list_path) |
| 124 | |
| 125 | for dut_attribute in dut_attr_list.dut_attributes: |
| 126 | update_dut_attribute(dut_attribute, get_ufs_project(env)) |
| 127 | |
| 128 | |
| 129 | def update_dut_attribute(attr, project): |
| 130 | """Take a DutAttribute and store it in the UFS datastore as a DutAttributeEntity.""" |
| 131 | eid = attr.id.value |
| 132 | logging.info('update_dut_attribute: handling %s', eid) |
| 133 | |
| 134 | client = datastore.Client(project=project,) |
| 135 | key = client.key(DUT_ATTRIBUTE_KIND, eid) |
| 136 | entity = datastore.Entity( |
| 137 | key=key, |
| 138 | exclude_from_indexes=['AttributeData'], |
| 139 | ) |
| 140 | entity['AttributeData'] = attr.SerializeToString() |
| 141 | entity['updated'] = datetime.datetime.now() |
| 142 | |
| 143 | logging.info('update_dut_attribute: putting entity into datastore for %s', |
| 144 | eid) |
| 145 | client.put(entity) |
Justin Suen | f9095ee | 2021-06-25 18:25:44 +0000 | [diff] [blame] | 146 | |
| 147 | |
| 148 | if __name__ == '__main__': |
| 149 | logging.basicConfig(level=logging.INFO) |
| 150 | parser = argparse.ArgumentParser( |
| 151 | description=__doc__, |
| 152 | formatter_class=argparse.RawDescriptionHelpFormatter, |
| 153 | ) |
| 154 | |
| 155 | parser.add_argument( |
Justin Suen | f9095ee | 2021-06-25 18:25:44 +0000 | [diff] [blame] | 156 | '--env', |
| 157 | type=str, |
| 158 | default='dev', |
| 159 | help='environment flag for UFS service', |
| 160 | ) |
| 161 | |
| 162 | # load database of protobuffer name -> Type |
| 163 | protodb = proto_utils.create_symbol_db() |
Justin Suen | f9095ee | 2021-06-25 18:25:44 +0000 | [diff] [blame] | 164 | options = parser.parse_args() |
Justin Suen | f9095ee | 2021-06-25 18:25:44 +0000 | [diff] [blame] | 165 | |
Justin Suen | 84529bd | 2021-07-22 18:06:48 +0000 | [diff] [blame] | 166 | handle_config_bundle_list("hw_design/generated/configs.jsonproto", |
| 167 | options.env) |
| 168 | handle_dut_attribute_list("dut_attributes/generated/dut_attributes.jsonproto", |
| 169 | options.env) |
Justin Suen | 5aaa7cd | 2021-09-01 08:55:53 +0000 | [diff] [blame^] | 170 | handle_flat_config_list("hw_design/generated/flattened.jsonproto", |
| 171 | options.env) |