Repository: google/cloud-forensics-utils

Issue:
Improve usability of new GCP functionality
Improve structure of objects returned from:
* `GoogleComputeInstance.GetEffectiveFirewallRules`
* `GoogleCloudMonitoring.GetCpuUsage`


Discussion:
codecov-commenter: # [Codecov](https://codecov.io/gh/google/cloud-forensics-utils/pull/381?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google) Report
> :exclamation: No coverage uploaded for pull request base (`main@ab100f1`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google#section-missing-base-commit).
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/google/cloud-forensics-utils/pull/381/graphs/tree.svg?width=650&height=150&src=pr&token=zZkPno3ah0&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google)](https://codecov.io/gh/google/cloud-forensics-utils/pull/381?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google)

```diff
@@           Coverage Diff           @@
##             main     #381   +/-   ##
=======================================
  Coverage        ?   61.29%           
=======================================
  Files           ?       40           
  Lines           ?     3201           
  Branches        ?        0           
=======================================
  Hits            ?     1962           
  Misses          ?     1239           
  Partials        ?        0           
```

| Flag | Coverage Δ | |
|---|---|---|
| nosetests | `61.29% <0.00%> (?)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google#carryforward-flags-in-the-pull-request-comment) to find out more.


------

[Continue to review full report at Codecov](https://codecov.io/gh/google/cloud-forensics-utils/pull/381?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/google/cloud-forensics-utils/pull/381?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google). Last update [ab100f1...9d95aff](https://codecov.io/gh/google/cloud-forensics-utils/pull/381?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=google).


Patch:
diff --git a/libcloudforensics/providers/gcp/internal/cloudresourcemanager.py b/libcloudforensics/providers/gcp/internal/cloudresourcemanager.py
index 175089f..d908745 100644
--- a/libcloudforensics/providers/gcp/internal/cloudresourcemanager.py
+++ b/libcloudforensics/providers/gcp/internal/cloudresourcemanager.py
@@ -22,11 +22,24 @@ if TYPE_CHECKING:
 
 
 class GoogleCloudResourceManager:
-  """Class to call the Google Cloud Resource Manager API."""
+  """Class to call the Google Cloud Resource Manager API.
+
+  Attributes:
+    project_id: Google Cloud project ID.
+  """
 
   RESOURCE_MANAGER_API_VERSION = 'v3'
   RESOURCE_TYPES = ['projects', 'folders', 'organizations']
 
+  def __init__(self, project_id: str) -> None:
+    """Initialize the GoogleCloudResourceManager object.
+
+    Args:
+      project_id (str): Google Cloud project ID.
+    """
+
+    self.project_id = project_id
+
   def GrmApi(self) -> 'googleapiclient.discovery.Resource':
     """Get a Resource Manager service object.
 
@@ -38,18 +51,15 @@ class GoogleCloudResourceManager:
     return common.CreateService(
         'cloudresourcemanager', self.RESOURCE_MANAGER_API_VERSION)
 
-  def ProjectAncestry(self, project_number: str) -> List[Any]:
+  def ProjectAncestry(self) -> List[Any]:
     """List ancestor resources for a project.
 
-    Args:
-      project_number (str): The project number to list ancestry for.
-
     Returns:
       List[Any]: the list of ancestor resources.
     """
 
     ancestry = []
-    current_resource = self.GetResource('projects/' + project_number)
+    current_resource = self.GetResource('projects/' + self.project_id)
     ancestry.append(current_resource)
 
     while 'parent' in current_resource:
diff --git a/libcloudforensics/providers/gcp/internal/compute.py b/libcloudforensics/providers/gcp/internal/compute.py
index 34c2da1..1c6978d 100644
--- a/libcloudforensics/providers/gcp/internal/compute.py
+++ b/libcloudforensics/providers/gcp/internal/compute.py
@@ -1267,6 +1267,30 @@ class GoogleComputeInstance(compute_base_resource.GoogleComputeBaseResource):
       raise errors.ServiceAccountRemovalError('Service account detatchment '
           'failure: {0:s}'.format(str(exception)), __name__)
 
+  def GetEffectiveFirewalls(self) -> List[Dict[str, Any]]:
+    """Get the raw effective firewalls for every interface:
+    https://cloud.google.com/compute/docs/reference/rest/v1/instances/getEffectiveFirewalls
+
+    Returns:
+      List[Dict[str, Any]]: The effective firewall rules per interface.
+    """
+    gce_instance_client = self.GceApi().instances()
+    instance_info = self.GetOperation()
+    effective_firewalls = []
+
+    for interface in instance_info.get('networkInterfaces', []):
+      interface_name = interface['name']
+      request = {'project': self.project_id, 'instance': self.name,
+          'zone': self.zone, 'networkInterface': interface_name}
+      # Safe to unpack, response not paginated.
+      response = common.ExecuteRequest(
+          gce_instance_client, 'getEffectiveFirewalls', request)[0]
+      effective_firewalls.append({
+          'interface_name': interface_name,
+          'firewalls': response})
+
+    return effective_firewalls
+
   def _NormaliseFirewallL4Config(self, l4config: List[Any]) -> List[Any]:
     """Normalise l4config dict key names that differ between policies and
     firewalls.
@@ -1289,14 +1313,14 @@ class GoogleComputeInstance(compute_base_resource.GoogleComputeBaseResource):
 
     return normalised_l4config
 
-  def _NormaliseFirewallRules(self, nic_rules: Dict[str, Any]) -> List[Any]:
-    """Normalise firewall policies and firewall rules into a common format.
+  def _NormaliseFirewalls(self, interface_rules: Dict[str, Any]) -> List[Any]:
+    """Normalise firewall policies and VPC firewalls into a common format.
 
     Args:
-      nic_rules: the effective firewall rules for an individual NIC.
+      interface_rules: the effective firewalls for an interface.
 
     Returns:
-      List[Dict[str, Any]]: The normalised firewall rules for a NIC with
+      List[Dict[str, Any]]: The normalised firewall rules for an interface with
         individual rules in the following format:
         {
           'type': 'policy' or 'firewall',
@@ -1314,8 +1338,8 @@ class GoogleComputeInstance(compute_base_resource.GoogleComputeBaseResource):
     """
 
     normalised_rules = []
-    firewall_policies = nic_rules['firewallPolicys']
-    firewalls = nic_rules['firewalls']
+    firewall_policies = interface_rules.get('firewallPolicys', [])
+    firewalls = interface_rules.get('firewalls', [])
 
     for policy_level, policy in enumerate(firewall_policies):
       for rule in policy['rules']:
@@ -1349,28 +1373,22 @@ class GoogleComputeInstance(compute_base_resource.GoogleComputeBaseResource):
 
     return normalised_rules
 
-  def GetEffectiveFirewallRules(self) -> Dict[str, List[Any]]:
-    """Get the effective firewall rules for an instance.
+  def GetNormalisedFirewalls(self) -> List[Dict[str, Any]]:
+    """Get normalised effective firewalls for every interface with firewall
+    policies and normal VPC firewalls collapsed into a single list.
 
     Returns:
-      Dict[str, List[Any]]: The effective firewall rules per NIC.
+      List[Dict[str, Any]]: The normalised firewalls per interface.
     """
-    gce_instance_client = self.GceApi().instances()
-    instance_info = self.GetOperation()
-    fw_rules = {}
+    effective_firewalls = self.GetEffectiveFirewalls()
+    normalised_firewalls = []
 
-    for nic in instance_info.get('networkInterfaces', []):
-      nic_name = nic['name']
-      nic_fw_rules = []
-      request = {'project': self.project_id, 'instance': self.name,
-          'zone': self.zone, 'networkInterface': nic_name}
-      responses = common.ExecuteRequest(
-          gce_instance_client, 'getEffectiveFirewalls', request)
-      for response in responses:
-        nic_fw_rules.extend(self._NormaliseFirewallRules(response))
-      fw_rules[nic_name] = nic_fw_rules
-
-    return fw_rules
+    for interface in effective_firewalls:
+      normalised_firewalls.append({
+          'interface_name': interface['interface_name'],
+          'firewalls': self._NormaliseFirewalls(interface['firewalls'])})
+
+    return normalised_firewalls
 
   def GetNatIps(self) -> List[str]:
     """Get the NAT external IPv4 addresses attached to an instance.
diff --git a/libcloudforensics/providers/gcp/internal/monitoring.py b/libcloudforensics/providers/gcp/internal/monitoring.py
index a90644d..191828b 100644
--- a/libcloudforensics/providers/gcp/internal/monitoring.py
+++ b/libcloudforensics/providers/gcp/internal/monitoring.py
@@ -15,7 +15,7 @@
 """Google Cloud Monitoring functionality."""
 
 import datetime
-from typing import TYPE_CHECKING, Dict, List, Tuple, Optional
+from typing import TYPE_CHECKING, Dict, List, Optional, Any
 
 from libcloudforensics.providers.gcp.internal import common
 
@@ -91,49 +91,60 @@ class GoogleCloudMonitoring:
               ret[service] = int(val)
     return ret
 
-  def _BuildCpuUsageFilter(self, instances: Optional[List[str]]) -> str:
-    """Builds a metrics query filter based on a list of instances.
+  def _BuildCpuUsageFilter(self, instance_ids: Optional[List[str]]) -> str:
+    """Builds a metrics query filter based on a list of instance IDs.
 
     Args:
-      instances list[str]: a list of instance names.
+      instance_ids list[str]: a list of instance ids.
 
     Returns:
       str: the filter to use in a metrics query.
     """
     instances_filter = (
           ['metric.type = "compute.googleapis.com/instance/cpu/utilization"'])
-    if instances:
+    if instance_ids:
       instances_filter.append(
-          ' AND (metric.label.instance_name = "{0:s}"'.format(instances[0]))
-      if len(instances) > 1:
-        for instance_name in instances[1:]:
+          ' AND (resource.label.instance_id = "{0:s}"'.format(instance_ids[0]))
+      if len(instance_ids) > 1:
+        for instance_name in instance_ids[1:]:
           instances_filter.append(
-              ' OR metric.label.instance_name = "{0:s}"'.format(instance_name))
+              ' OR resource.label.instance_id = "{0:s}"'.format(instance_name))
       instances_filter.append(')')
 
     return ''.join(instances_filter)
 
   def GetCpuUsage(self,
-    instances: Optional[List[str]] = None,
+    instance_ids: Optional[List[str]] = None,
     days: int = 7,
     aggregation_minutes: int = 60
-    ) -> Dict[str, List[Tuple[str, float]]]:
+    ) -> List[Dict[str, Any]]:
     """Returns CPU usage metrics for compute instances.
 
     By default returns hourly usage for the last seven days for all instances
     within a project.
 
     Args:
-      instances list[str]: Optional. A list of instance names to collect
+      instance_ids list[str]: Optional. A list of instance IDs to collect
         metrics for. When not provided will collect metrics for all instances
         in the project.
       days (int): Optional. The number of days to collect metrics for.
       aggregate_minutes (int): Optional. The minutes to aggregate on.
 
     Returns:
-      Dict[str, List[Tuple[str, float]]]: the CPU usage for the instances with
-        instancename_instanceid as the key and (timestamp, usage) tuples
-        as values.
+      List[Dict[str, Any]]: a list of CPU usage for each instance in the format
+        [
+          {
+            'instance_name': str,
+            'instance_id': str,
+            'cpu_usage':
+            [
+              {
+                'timestamp': str,
+                'cpu_usage': float
+              },
+            ]
+          },
+        ]
     """
     service = self.GcmApi()
     gcm_timeseries_client = service.projects().timeSeries() # pylint: disable=no-member
@@ -142,7 +153,7 @@ class GoogleCloudMonitoring:
         datetime.datetime.utcnow() - datetime.timedelta(days=days))
     end_time = common.FormatRFC3339(datetime.datetime.utcnow())
     period = aggregation_minutes * 60
-    instance_filter = self._BuildCpuUsageFilter(instances)
+    instance_filter = self._BuildCpuUsageFilter(instance_ids)
 
     responses = common.ExecuteRequest(gcm_timeseries_client, 'list', {
         'name': 'projects/{0:s}'.format(self.project_id),
@@ -154,20 +165,23 @@ class GoogleCloudMonitoring:
         'aggregation_alignmentPeriod': '{0:d}s'.format(period),
     })
 
-    cpu_usage_instances = {}
+    cpu_usage_instances = []
 
     for response in responses:
       time_series = response.get('timeSeries', [])
       for ts in time_series:
         instance_name = ts['metric']['labels']['instance_name']
         instance_id = ts['resource']['labels']['instance_id']
-        instance_key = instance_name + '_' + instance_id # type: str
         points = ts['points']
-        parsed_points = []
+        cpu_usage = []
         for point in points:
-          timestamp = point['interval']['startTime'] # type: str
-          cpu_usage = point['value']['doubleValue'] # type: float
-          parsed_points.append((timestamp, cpu_usage))
-        cpu_usage_instances[instance_key] = parsed_points
+          cpu_usage.append({
+              'timestamp': point['interval']['startTime'],
+              'cpu_usage': point['value']['doubleValue']})
+
+        cpu_usage_instances.append({
+            'instance_name': instance_name,
+            'instance_id': instance_id,
+            'cpu_usage': cpu_usage})
 
     return cpu_usage_instances
diff --git a/libcloudforensics/providers/gcp/internal/project.py b/libcloudforensics/providers/gcp/internal/project.py
index 6c53d68..d54b0fa 100644
--- a/libcloudforensics/providers/gcp/internal/project.py
+++ b/libcloudforensics/providers/gcp/internal/project.py
@@ -29,7 +29,10 @@ import libcloudforensics.providers.gcp.internal.storage as storage_module
 import libcloudforensics.providers.gcp.internal.storagetransfer\
   as storagetransfer_module
 import libcloudforensics.providers.gcp.internal.cloudsql as cloudsql_module
-
+import libcloudforensics.providers.gcp.internal.cloudresourcemanager\
+  as cloudresourcemanager_module
+import libcloudforensics.providers.gcp.internal.serviceusage\
+  as serviceusage_module
 
 class GoogleCloudProject:
   """Class representing a Google Cloud Project.
@@ -79,8 +82,10 @@ class GoogleCloudProject:
     # pylint: disable=line-too-long
     self._storagetransfer = None  # type: Optional[storagetransfer_module.GoogleCloudStorageTransfer]
     self._monitoring = None  # type: Optional[monitoring_module.GoogleCloudMonitoring]
-    # pylint: enable=line-too-long
     self._cloudsql = None  # type: Optional[cloudsql_module.GoogleCloudSQL]
+    self._cloudresourcemanager = None  # type: Optional[cloudresourcemanager_module.GoogleCloudResourceManager]
+    self._serviceusage = None  # type: Optional[serviceusage_module.GoogleServiceUsage]
+    # pylint: enable=line-too-long
 
   @property
   def compute(self) -> compute_module.GoogleCloudCompute:
@@ -208,3 +213,34 @@ class GoogleCloudProject:
     self._cloudsql = cloudsql_module.GoogleCloudSQL(
         self.project_id)
     return self._cloudsql
+
+  @property
+  def cloudresourcemanager(
+      self) -> cloudresourcemanager_module.GoogleCloudResourceManager:
+    """Get a GoogleCloudResourceManager object for the project.
+
+    Returns:
+      GoogleCloudResourceManager: Object that represents Google cloud resource
+        manager.
+    """
+
+    if self._cloudresourcemanager:
+      return self._cloudresourcemanager
+    self._cloudresourcemanager = (
+        cloudresourcemanager_module.GoogleCloudResourceManager(
+            self.project_id))
+    return self._cloudresourcemanager
+
+  @property
+  def serviceusage(self) -> serviceusage_module.GoogleServiceUsage:
+    """Get a GoogleServiceUsage object for the project.
+
+    Returns:
+      GoogleServiceUsage: Object that represents Google service usage.
+    """
+
+    if self._serviceusage:
+      return self._serviceusage
+    self._serviceusage = serviceusage_module.GoogleServiceUsage(
+        self.project_id)
+    return self._serviceusage
diff --git a/libcloudforensics/providers/gcp/internal/serviceusage.py b/libcloudforensics/providers/gcp/internal/serviceusage.py
index 7de6f92..6d853a0 100644
--- a/libcloudforensics/providers/gcp/internal/serviceusage.py
+++ b/libcloudforensics/providers/gcp/internal/serviceusage.py
@@ -22,10 +22,23 @@ if TYPE_CHECKING:
 
 
 class GoogleServiceUsage:
-  """Class to call the Google Cloud Service Usage API."""
+  """Class to call the Google Cloud Service Usage API.
+
+  Attributes:
+    project_id: Google Cloud project ID.
+  """
 
   SERVICE_USAGE_API_VERSION = 'v1'
 
+  def __init__(self, project_id: str) -> None:
+    """Initialize the GoogleServiceUsage object.
+
+    Args:
+      project_id (str): Google Cloud project ID.
+    """
+
+    self.project_id = project_id
+
   def GsuApi(self) -> 'googleapiclient.discovery.Resource':
     """Get a Service Usage service object.
 
@@ -36,18 +49,15 @@ class GoogleServiceUsage:
     return common.CreateService(
         'serviceusage', self.SERVICE_USAGE_API_VERSION)
 
-  def GetEnabled(self, project_number: str) -> List[Any]:
+  def GetEnabled(self) -> List[Any]:
     """Get enabled services/APIs for a project.
 
-    Args:
-      project_number (str): The project_number to fetch enabled APIs for.
-
     Returns:
       List[Any]: A list of enabled services/APIs.
     """
 
     services_client = self.GsuApi().services() # pylint: disable=no-member
-    parent = 'projects/' + project_number
+    parent = 'projects/' + self.project_id
     request = {'parent': parent, 'filter': 'state:ENABLED'}
     responses = common.ExecuteRequest(services_client, 'list', request)
 
@@ -58,28 +68,26 @@ class GoogleServiceUsage:
 
     return services
 
-  def EnableService(self, project_number: str, service_name: str) -> None:
+  def EnableService(self, service_name: str) -> None:
     """Enable a service/API for a project.
 
     Args:
-      project_number (str): The project_number to enable the service for.
       service_name (str): The service to enable.
     """
 
     services_client = self.GsuApi().services() # pylint: disable=no-member
-    name = 'projects/' + project_number + '/services/' + service_name
+    name = 'projects/' + self.project_id + '/services/' + service_name
     request = {'name': name}
     common.ExecuteRequest(services_client, 'enable', request)
 
-  def DisableService(self, project_number: str, service_name: str) -> None:
+  def DisableService(self, service_name: str) -> None:
     """Disable a service/API for a project.
 
     Args:
-      project_number (str): The project_number to disable the service for.
       service_name (str): The service to disable.
     """
 
     services_client = self.GsuApi().services() # pylint: disable=no-member
-    name = 'projects/' + project_number + '/services/' + service_name
+    name = 'projects/' + self.project_id + '/services/' + service_name
     request = {'name': name}
     common.ExecuteRequest(services_client, 'disable', request)


Test patch:
diff --git a/tests/providers/gcp/gcp_mocks.py b/tests/providers/gcp/gcp_mocks.py
index ea5c65c..f6e4ba9 100644
--- a/tests/providers/gcp/gcp_mocks.py
+++ b/tests/providers/gcp/gcp_mocks.py
@@ -25,7 +25,7 @@ from libcloudforensics.providers.gcp.internal import monitoring as gcp_monitorin
 from libcloudforensics.providers.gcp.internal import storage as gcp_storage
 from libcloudforensics.providers.gcp.internal import storagetransfer as gcp_storagetransfer
 from libcloudforensics.providers.gcp.internal import cloudsql as gcp_cloudsql
-from libcloudforensics.providers.gcp.internal import cloudresourcemanager as gcp_resourcmanager
+from libcloudforensics.providers.gcp.internal import cloudresourcemanager as gcp_resourcemanager
 from libcloudforensics.providers.gcp.internal import serviceusage as gcp_serviceusage
 # pylint: enable=line-too-long
 
@@ -85,8 +85,8 @@ FAKE_GCST = gcp_storagetransfer.GoogleCloudStorageTransfer('fake-target-project'
 FAKE_GCB = gcp_build.GoogleCloudBuild('fake-target-project')
 FAKE_MONITORING = gcp_monitoring.GoogleCloudMonitoring('fake-target-project')
 FAKE_CLOUDSQLINSTANCE = gcp_cloudsql.GoogleCloudSQL('fake-target-project')
-FAKE_CLOUD_RESOURCE_MANAGER = gcp_resourcmanager.GoogleCloudResourceManager()
-FAKE_SERVICE_USAGE = gcp_serviceusage.GoogleServiceUsage()
+FAKE_CLOUD_RESOURCE_MANAGER = gcp_resourcemanager.GoogleCloudResourceManager('fake-project')
+FAKE_SERVICE_USAGE = gcp_serviceusage.GoogleServiceUsage('fake-project')
 # pylint: enable=line-too-long
 
 # Mock struct to mimic GCP's API responses
@@ -559,7 +559,7 @@ MOCK_GCM_METRICS_CPU = {
             'resource': {
                 'type': 'gce_instance',
                 'labels': {
-                    'instance_id': '0000000000000000000',
+                    'instance_id': '0000000000000000001',
                     'zone': 'us-central1-a',
                     'project_id': 'fake-project'
                 }
@@ -578,7 +578,7 @@ MOCK_GCM_METRICS_CPU = {
             'resource': {
                 'type': 'gce_instance',
                 'labels': {
-                    'instance_id': '0000000000000000000',
+                    'instance_id': '0000000000000000002',
                     'zone': 'us-central1-a',
                     'project_id': 'fake-project'
                 }
diff --git a/tests/providers/gcp/internal/test_cloudresourcemanager.py b/tests/providers/gcp/internal/test_cloudresourcemanager.py
index 40d3a1a..e005b60 100644
--- a/tests/providers/gcp/internal/test_cloudresourcemanager.py
+++ b/tests/providers/gcp/internal/test_cloudresourcemanager.py
@@ -68,8 +68,7 @@ class GoogleCloudResourceManagerTest(unittest.TestCase):
         [gcp_mocks.MOCK_CLOUD_RESOURCE_FOLDER],
         [gcp_mocks.MOCK_CLOUD_RESOURCE_ORGANIZATION]
     ]
-    response = gcp_mocks.FAKE_CLOUD_RESOURCE_MANAGER.ProjectAncestry(
-        '000000000000')
+    response = gcp_mocks.FAKE_CLOUD_RESOURCE_MANAGER.ProjectAncestry()
     self.assertListEqual(response,
         [
           {
diff --git a/tests/providers/gcp/internal/test_compute.py b/tests/providers/gcp/internal/test_compute.py
index c0ddca5..952ca02 100644
--- a/tests/providers/gcp/internal/test_compute.py
+++ b/tests/providers/gcp/internal/test_compute.py
@@ -399,42 +399,48 @@ class GoogleComputeInstanceTest(unittest.TestCase):
   @typing.no_type_check
   @mock.patch('libcloudforensics.providers.gcp.internal.compute.GoogleComputeInstance.GetOperation')
   @mock.patch('libcloudforensics.providers.gcp.internal.common.GoogleCloudComputeClient.GceApi')
-  def testGetEffectiveFirewallRules(self, mock_gce_api, mock_get_operation):
+  def testGetNormalisedFirewalls(self, mock_gce_api, mock_get_operation):
     """Tests that firewall rules are properly formatted"""
     mock_get_operation.return_value = {'networkInterfaces': gcp_mocks.MOCK_NETWORK_INTERFACES}
     mock_gce_api.return_value.instances.return_value.getEffectiveFirewalls.return_value.execute.return_value = gcp_mocks.MOCK_EFFECTIVE_FIREWALLS
-    fw_rules = gcp_mocks.FAKE_INSTANCE.GetEffectiveFirewallRules()
-    self.assertDictEqual(
-      fw_rules,
-      {'nic0': [
-        {
-          'type': 'policy',
-          'policy_level': 0,
-          'priority': 1,
-          'direction': 'INGRESS',
-          'l4config': [{'ip_protocol': 'tcp'}],
-          'ips': ['8.8.8.8/24'],
-          'action': 'allow'
-        },
-        {
-          'type': 'policy',
-          'policy_level': 1,
-          'priority': 1,
-          'direction': 'INGRESS',
-          'l4config': [{'ip_protocol': 'tcp'}],
-          'ips': ['8.8.4.4/24'],
-          'action': 'goto_next'
-        },
+    normalised_firewalls = gcp_mocks.FAKE_INSTANCE.GetNormalisedFirewalls()
+    self.assertListEqual(
+      normalised_firewalls,
+      [
         {
-          'type': 'firewall',
-          'policy_level': 999,
-          'priority': 1000,
-          'direction': 'INGRESS',
-          'l4config': [{'ip_protocol': 'tcp'}],
-          'ips': ['0.0.0.0/0'],
-          'action':
-          'allow'
-        }]})
+          'interface_name': 'nic0',
+          'firewalls': [
+            {
+              'type': 'policy',
+              'policy_level': 0,
+              'priority': 1,
+              'direction': 'INGRESS',
+              'l4config': [{'ip_protocol': 'tcp'}],
+              'ips': ['8.8.8.8/24'],
+              'action': 'allow'
+            },
+            {
+              'type': 'policy',
+              'policy_level': 1,
+              'priority': 1,
+              'direction': 'INGRESS',
+              'l4config': [{'ip_protocol': 'tcp'}],
+              'ips': ['8.8.4.4/24'],
+              'action': 'goto_next'
+            },
+            {
+              'type': 'firewall',
+              'policy_level': 999,
+              'priority': 1000,
+              'direction': 'INGRESS',
+              'l4config': [{'ip_protocol': 'tcp'}],
+              'ips': ['0.0.0.0/0'],
+              'action':
+              'allow'
+            }
+          ]
+        }
+      ])
 
   @typing.no_type_check
   @mock.patch('libcloudforensics.providers.gcp.internal.compute.GoogleComputeInstance.GetOperation')
diff --git a/tests/providers/gcp/internal/test_monitoring.py b/tests/providers/gcp/internal/test_monitoring.py
index 52005c6..4db3b9b 100644
--- a/tests/providers/gcp/internal/test_monitoring.py
+++ b/tests/providers/gcp/internal/test_monitoring.py
@@ -47,11 +47,12 @@ class GoogleCloudMonitoringTest(unittest.TestCase):
     """Validates the query filter builder functionality"""
     # pylint: disable=protected-access
     instances_filter = gcp_mocks.FAKE_MONITORING._BuildCpuUsageFilter(
-        ['instance-a', 'instance-b'])
+        ['0000000000000000001', '0000000000000000002'])
     self.assertEqual(
         instances_filter, ('metric.type = "compute.googleapis.com/instance/'
-        'cpu/utilization" AND (metric.label.instance_name = "instance-a" OR '
-        'metric.label.instance_name = "instance-b")'))
+        'cpu/utilization" AND (resource.label.instance_id = '
+        '"0000000000000000001" OR resource.label.instance_id = '
+        '"0000000000000000002")'))
 
   @typing.no_type_check
   @mock.patch('libcloudforensics.providers.gcp.internal.monitoring.GoogleCloudMonitoring.GcmApi')
@@ -60,8 +61,29 @@ class GoogleCloudMonitoringTest(unittest.TestCase):
     services = mock_gcm_api.return_value.projects.return_value.timeSeries.return_value.list
     services.return_value.execute.return_value = gcp_mocks.MOCK_GCM_METRICS_CPU
     cpu_usage = gcp_mocks.FAKE_MONITORING.GetCpuUsage()
-    self.assertEqual(len(cpu_usage), 2)
-    self.assertIn('instance-a_0000000000000000000', cpu_usage)
-    self.assertEqual(
-        cpu_usage['instance-a_0000000000000000000'],
-        [('2021-01-01T00:00:00.000000Z', 0.100000000000000000)] * 24*7)
+    self.assertEqual(2, len(cpu_usage))
+    self.assertListEqual(cpu_usage,
+        [
+          {
+            'instance_name': 'instance-a',
+            'instance_id': '0000000000000000001',
+            'cpu_usage':
+              [
+                {
+                  'timestamp': '2021-01-01T00:00:00.000000Z',
+                  'cpu_usage': 0.1
+                }
+              ] * 24 * 7
+          },
+          {
+            'instance_name': 'instance-b',
+            'instance_id': '0000000000000000002',
+            'cpu_usage':
+              [
+                {
+                  'timestamp': '2021-01-01T00:00:00.000000Z',
+                  'cpu_usage': 0.1
+                }
+              ] * 24 * 7
+          }
+        ])
diff --git a/tests/providers/gcp/internal/test_serviceusage.py b/tests/providers/gcp/internal/test_serviceusage.py
index bbf1e37..b4c7413 100644
--- a/tests/providers/gcp/internal/test_serviceusage.py
+++ b/tests/providers/gcp/internal/test_serviceusage.py
@@ -32,10 +32,10 @@ class GoogleServiceUsageTest(unittest.TestCase):
     """Validates the GetEnabled function"""
     mock_execute_request.return_value = gcp_mocks.MOCK_ENABLED_SERVICES
     mock_service_usage = mock_gsu_api.return_value.services.return_value
-    response = gcp_mocks.FAKE_SERVICE_USAGE.GetEnabled('000000000000')
+    response = gcp_mocks.FAKE_SERVICE_USAGE.GetEnabled()
 
     mock_execute_request.assert_called_with(mock_service_usage,
-        'list', {'parent': 'projects/000000000000', 'filter': 'state:ENABLED'})
+        'list', {'parent': 'projects/fake-project', 'filter': 'state:ENABLED'})
 
     self.assertListEqual(response, [
         'bigquery.googleapis.com',
@@ -50,11 +50,10 @@ class GoogleServiceUsageTest(unittest.TestCase):
     """Validates that EnableService calls ExecuteRequest with the correct
     arguments."""
     mock_service_usage = mock_gsu_api.return_value.services.return_value
-    gcp_mocks.FAKE_SERVICE_USAGE.EnableService(
-        '000000000000','container.googleapis.com')
+    gcp_mocks.FAKE_SERVICE_USAGE.EnableService('container.googleapis.com')
 
     mock_execute_request.assert_called_with(mock_service_usage, 'enable',
-        {'name': 'projects/000000000000/services/container.googleapis.com'})
+        {'name': 'projects/fake-project/services/container.googleapis.com'})
 
   @typing.no_type_check
   @mock.patch('libcloudforensics.providers.gcp.internal.common.ExecuteRequest')
@@ -63,8 +62,7 @@ class GoogleServiceUsageTest(unittest.TestCase):
     """Validates that DisableService calls ExecuteRequest with the correct
     arguments."""
     mock_service_usage = mock_gsu_api.return_value.services.return_value
-    gcp_mocks.FAKE_SERVICE_USAGE.DisableService(
-        '000000000000','container.googleapis.com')
+    gcp_mocks.FAKE_SERVICE_USAGE.DisableService('container.googleapis.com')
 
     mock_execute_request.assert_called_with(mock_service_usage, 'disable',
-        {'name': 'projects/000000000000/services/container.googleapis.com'})
+        {'name': 'projects/fake-project/services/container.googleapis.com'})