gcpdiag.queries.osconfig

Queries related to GCP OS Config
class Inventory(gcpdiag.models.Resource):
29class Inventory(models.Resource):
30  """Represents OS Inventory data of a GCE VM instance"""
31
32  _resource_data: dict
33
34  def __init__(self, project_id, resource_data):
35    super().__init__(project_id=project_id)
36    self._resource_data = resource_data
37
38  # e.g: projects/{project_number}/locations/{location}/instances/{instance_id}/inventory
39  @property
40  def full_path(self) -> str:
41    return self._resource_data['name']
42
43  # e.g: {project_number}/{location}/{instance_id}/inventory
44  @property
45  def short_path(self) -> str:
46    path = self.full_path
47    path = re.sub(r'^projects/', '', path)
48    path = re.sub(r'/locations/', '/', path)
49    path = re.sub(r'/instances/', '/', path)
50    return path
51
52  # e.g: '5221437597918447050'
53  @property
54  def instance_id(self) -> str:
55    return self._resource_data['name'].split('/')[-2]
56
57  # e.g: debian, windows.
58  @property
59  def os_shortname(self) -> str:
60    if 'osInfo' in self._resource_data:
61      return self._resource_data['osInfo'].get('shortName', '')
62    return ''
63
64  @property
65  def os_version(self) -> str:
66    if 'osInfo' in self._resource_data:
67      return self._resource_data['osInfo'].get('version', '')
68    return ''
69
70  # <key: installed package name, value: installed version>
71  @property
72  def installed_packages(self) -> Mapping[str, str]:
73    installed_packages: Dict[str, str] = {}
74    if 'items' in self._resource_data:
75      installed_items = [
76        i for i in self._resource_data['items'].values() if i.get('type', '') == 'INSTALLED_PACKAGE'
77      ]
78      for item in installed_items:
79        if 'installedPackage' not in item:
80          continue
81        pkg = item['installedPackage']
82        if 'yumPackage' in pkg:
83          p = pkg['yumPackage']
84          installed_packages[p.get('packageName', '')] = p.get('version', '')
85        elif 'aptPackage' in pkg:
86          p = pkg['aptPackage']
87          installed_packages[p.get('packageName', '')] = p.get('version', '')
88        elif 'googetPackage' in pkg:
89          p = pkg['googetPackage']
90          installed_packages[p.get('packageName', '')] = p.get('version', '')
91        elif 'windowsApplication' in pkg:
92          p = pkg['windowsApplication']
93          installed_packages[p.get('displayName', '')] = p.get('displayVersion', '')
94    return installed_packages

Represents OS Inventory data of a GCE VM instance

Inventory(project_id, resource_data)
34  def __init__(self, project_id, resource_data):
35    super().__init__(project_id=project_id)
36    self._resource_data = resource_data
full_path: str
39  @property
40  def full_path(self) -> str:
41    return self._resource_data['name']

Returns the full path of this resource.

Example: 'projects/gcpdiag-gke-1-9b90/zones/europe-west4-a/clusters/gke1'

short_path: str
44  @property
45  def short_path(self) -> str:
46    path = self.full_path
47    path = re.sub(r'^projects/', '', path)
48    path = re.sub(r'/locations/', '/', path)
49    path = re.sub(r'/instances/', '/', path)
50    return path

Returns the short name for this resource.

Note that it isn't clear from this name what kind of resource it is.

Example: 'gke1'

instance_id: str
53  @property
54  def instance_id(self) -> str:
55    return self._resource_data['name'].split('/')[-2]
os_shortname: str
58  @property
59  def os_shortname(self) -> str:
60    if 'osInfo' in self._resource_data:
61      return self._resource_data['osInfo'].get('shortName', '')
62    return ''
os_version: str
64  @property
65  def os_version(self) -> str:
66    if 'osInfo' in self._resource_data:
67      return self._resource_data['osInfo'].get('version', '')
68    return ''
installed_packages: Mapping[str, str]
71  @property
72  def installed_packages(self) -> Mapping[str, str]:
73    installed_packages: Dict[str, str] = {}
74    if 'items' in self._resource_data:
75      installed_items = [
76        i for i in self._resource_data['items'].values() if i.get('type', '') == 'INSTALLED_PACKAGE'
77      ]
78      for item in installed_items:
79        if 'installedPackage' not in item:
80          continue
81        pkg = item['installedPackage']
82        if 'yumPackage' in pkg:
83          p = pkg['yumPackage']
84          installed_packages[p.get('packageName', '')] = p.get('version', '')
85        elif 'aptPackage' in pkg:
86          p = pkg['aptPackage']
87          installed_packages[p.get('packageName', '')] = p.get('version', '')
88        elif 'googetPackage' in pkg:
89          p = pkg['googetPackage']
90          installed_packages[p.get('packageName', '')] = p.get('version', '')
91        elif 'windowsApplication' in pkg:
92          p = pkg['windowsApplication']
93          installed_packages[p.get('displayName', '')] = p.get('displayVersion', '')
94    return installed_packages
@caching.cached_api_call(in_memory=True)
def list_inventories( context: gcpdiag.models.Context, location: str) -> Mapping[str, Inventory]:
 97@caching.cached_api_call(in_memory=True)
 98def list_inventories(
 99  context: models.Context,
100  location: str,
101) -> Mapping[str, Inventory]:
102  inventories: Dict[str, Inventory] = {}
103  if not apis.is_enabled(context.project_id, 'osconfig'):
104    return inventories
105  osconfig_api = apis.get_api('osconfig', 'v1', context.project_id)
106  logging.debug(
107    'fetching inventory data for all VMs under zone %s in project %s',
108    location,
109    context.project_id,
110  )
111  query = osconfig_api.projects().locations().instances().inventories()
112
113  try:
114    resp = apis_utils.list_all(
115      query.list(
116        parent=(f'projects/{context.project_id}/locations/{location}/instances/-'),
117        view='FULL',
118      ),
119      query.list_next,
120      'inventories',
121    )
122  except googleapiclient.errors.HttpError as err:
123    if err.resp.status in [404]:
124      return inventories
125    raise utils.GcpApiError(err) from err
126
127  for i in resp:
128    inventory = Inventory(context.project_id, resource_data=i)
129    inventories[inventory.instance_id] = inventory
130  return inventories
@caching.cached_api_call(in_memory=True)
def get_inventory( context: gcpdiag.models.Context, location: str, instance_name: str) -> Optional[Inventory]:
133@caching.cached_api_call(in_memory=True)
134def get_inventory(
135  context: models.Context, location: str, instance_name: str
136) -> Optional[Inventory]:
137  if not apis.is_enabled(context.project_id, 'osconfig'):
138    return None
139  osconfig_api = apis.get_api('osconfig', 'v1', context.project_id)
140  logging.debug(
141    'fetching inventory data for VM %s in zone %s in project %s',
142    instance_name,
143    location,
144    context.project_id,
145  )
146  query = (
147    osconfig_api.projects()
148    .locations()
149    .instances()
150    .inventories()
151    .get(
152      name=f'projects/{context.project_id}/locations/{location}/instances/{instance_name}/inventory',
153      view='FULL',
154    )
155  )
156  try:
157    resp = query.execute(num_retries=config.API_RETRIES)
158  except googleapiclient.errors.HttpError as err:
159    if err.resp.status in [404]:
160      return None
161    raise utils.GcpApiError(err) from err
162  return Inventory(context.project_id, resource_data=resp)