|
@@ -6,12 +6,13 @@ import inspect
|
|
|
import io
|
|
import io
|
|
|
import json
|
|
import json
|
|
|
import math
|
|
import math
|
|
|
-import re
|
|
|
|
|
import uuid
|
|
import uuid
|
|
|
|
|
|
|
|
import cloudbridge as cb
|
|
import cloudbridge as cb
|
|
|
|
|
+import cloudbridge.cloud.base.helpers as cb_helpers
|
|
|
from cloudbridge.cloud.base.resources import BaseAttachmentInfo
|
|
from cloudbridge.cloud.base.resources import BaseAttachmentInfo
|
|
|
from cloudbridge.cloud.base.resources import BaseBucket
|
|
from cloudbridge.cloud.base.resources import BaseBucket
|
|
|
|
|
+from cloudbridge.cloud.base.resources import BaseBucketContainer
|
|
|
from cloudbridge.cloud.base.resources import BaseBucketObject
|
|
from cloudbridge.cloud.base.resources import BaseBucketObject
|
|
|
from cloudbridge.cloud.base.resources import BaseFloatingIP
|
|
from cloudbridge.cloud.base.resources import BaseFloatingIP
|
|
|
from cloudbridge.cloud.base.resources import BaseFloatingIPContainer
|
|
from cloudbridge.cloud.base.resources import BaseFloatingIPContainer
|
|
@@ -143,15 +144,9 @@ class GCEVMType(BaseVMType):
|
|
|
|
|
|
|
|
class GCEPlacementZone(BasePlacementZone):
|
|
class GCEPlacementZone(BasePlacementZone):
|
|
|
|
|
|
|
|
- def __init__(self, provider, zone, region):
|
|
|
|
|
|
|
+ def __init__(self, provider, zone):
|
|
|
super(GCEPlacementZone, self).__init__(provider)
|
|
super(GCEPlacementZone, self).__init__(provider)
|
|
|
- if isinstance(zone, GCEPlacementZone):
|
|
|
|
|
- # pylint:disable=protected-access
|
|
|
|
|
- self._gce_zone = zone._gce_zone
|
|
|
|
|
- self._gce_region = zone._gce_region
|
|
|
|
|
- else:
|
|
|
|
|
- self._gce_zone = zone
|
|
|
|
|
- self._gce_region = region
|
|
|
|
|
|
|
+ self._zone = zone
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def id(self):
|
|
def id(self):
|
|
@@ -160,7 +155,7 @@ class GCEPlacementZone(BasePlacementZone):
|
|
|
:rtype: ``str``
|
|
:rtype: ``str``
|
|
|
:return: ID for this zone as returned by the cloud middleware.
|
|
:return: ID for this zone as returned by the cloud middleware.
|
|
|
"""
|
|
"""
|
|
|
- return self._gce_zone.get('selfLink')
|
|
|
|
|
|
|
+ return self._zone['selfLink']
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def name(self):
|
|
def name(self):
|
|
@@ -169,7 +164,7 @@ class GCEPlacementZone(BasePlacementZone):
|
|
|
:rtype: ``str``
|
|
:rtype: ``str``
|
|
|
:return: Name for this zone as returned by the cloud middleware.
|
|
:return: Name for this zone as returned by the cloud middleware.
|
|
|
"""
|
|
"""
|
|
|
- return self._gce_zone.get('name')
|
|
|
|
|
|
|
+ return self._zone['name']
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def region_name(self):
|
|
def region_name(self):
|
|
@@ -178,7 +173,8 @@ class GCEPlacementZone(BasePlacementZone):
|
|
|
:rtype: ``str``
|
|
:rtype: ``str``
|
|
|
:return: Name of this zone's region as returned by the cloud middleware
|
|
:return: Name of this zone's region as returned by the cloud middleware
|
|
|
"""
|
|
"""
|
|
|
- return self._gce_region
|
|
|
|
|
|
|
+ parsed_region_url = self._provider.parse_url(self._zone['region'])
|
|
|
|
|
+ return parsed_region_url.parameters['region']
|
|
|
|
|
|
|
|
|
|
|
|
|
class GCERegion(BaseRegion):
|
|
class GCERegion(BaseRegion):
|
|
@@ -207,8 +203,7 @@ class GCERegion(BaseRegion):
|
|
|
.execute())
|
|
.execute())
|
|
|
zones = [zone for zone in zones_response['items']
|
|
zones = [zone for zone in zones_response['items']
|
|
|
if zone['region'] == self._gce_region['selfLink']]
|
|
if zone['region'] == self._gce_region['selfLink']]
|
|
|
- return [GCEPlacementZone(self._provider, zone, self.name)
|
|
|
|
|
- for zone in zones]
|
|
|
|
|
|
|
+ return [GCEPlacementZone(self._provider, zone) for zone in zones]
|
|
|
|
|
|
|
|
|
|
|
|
|
class GCEFirewallsDelegate(object):
|
|
class GCEFirewallsDelegate(object):
|
|
@@ -711,28 +706,9 @@ class GCEMachineImage(BaseMachineImage):
|
|
|
Refreshes the state of this instance by re-querying the cloud provider
|
|
Refreshes the state of this instance by re-querying the cloud provider
|
|
|
for its latest state.
|
|
for its latest state.
|
|
|
"""
|
|
"""
|
|
|
- resource_link = self._gce_image['selfLink']
|
|
|
|
|
- project_pattern = 'projects/(.*?)/'
|
|
|
|
|
- match = re.search(project_pattern, resource_link)
|
|
|
|
|
- if match:
|
|
|
|
|
- project = match.group(1)
|
|
|
|
|
- else:
|
|
|
|
|
- cb.log.warning("Project name is not found.")
|
|
|
|
|
- return
|
|
|
|
|
- try:
|
|
|
|
|
- response = (self._provider
|
|
|
|
|
- .gce_compute
|
|
|
|
|
- .images()
|
|
|
|
|
- .get(project=project, image=self.name)
|
|
|
|
|
- .execute())
|
|
|
|
|
- if response:
|
|
|
|
|
- # pylint:disable=protected-access
|
|
|
|
|
- self._gce_image = response
|
|
|
|
|
- except googleapiclient.errors.HttpError as http_error:
|
|
|
|
|
- # image no longer exists
|
|
|
|
|
- cb.log.warning(
|
|
|
|
|
- "googleapiclient.errors.HttpError: {0}".format(http_error))
|
|
|
|
|
- self._gce_image['status'] = "unknown"
|
|
|
|
|
|
|
+ self._gce_image = self._provider.get_resource('images', self.id)
|
|
|
|
|
+ if not self._gce_image:
|
|
|
|
|
+ self._gce_image = {'status': 'UNKNOWN'}
|
|
|
|
|
|
|
|
|
|
|
|
|
class GCEInstance(BaseInstance):
|
|
class GCEInstance(BaseInstance):
|
|
@@ -753,6 +729,7 @@ class GCEInstance(BaseInstance):
|
|
|
def __init__(self, provider, gce_instance):
|
|
def __init__(self, provider, gce_instance):
|
|
|
super(GCEInstance, self).__init__(provider)
|
|
super(GCEInstance, self).__init__(provider)
|
|
|
self._gce_instance = gce_instance
|
|
self._gce_instance = gce_instance
|
|
|
|
|
+ self._inet_gateway = None
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def resource_url(self):
|
|
def resource_url(self):
|
|
@@ -805,7 +782,7 @@ class GCEInstance(BaseInstance):
|
|
|
access_config = access_configs[0]
|
|
access_config = access_configs[0]
|
|
|
if 'natIP' in access_config:
|
|
if 'natIP' in access_config:
|
|
|
ips.append(access_config['natIP'])
|
|
ips.append(access_config['natIP'])
|
|
|
- for ip in self._provider.networking.floating_ips:
|
|
|
|
|
|
|
+ for ip in self.inet_gateway.floating_ips:
|
|
|
if ip.in_use():
|
|
if ip.in_use():
|
|
|
if ip.private_ip in self.private_ips:
|
|
if ip.private_ip in self.private_ips:
|
|
|
ips.append(ip.public_ip)
|
|
ips.append(ip.public_ip)
|
|
@@ -846,46 +823,50 @@ class GCEInstance(BaseInstance):
|
|
|
"""
|
|
"""
|
|
|
Reboot this instance.
|
|
Reboot this instance.
|
|
|
"""
|
|
"""
|
|
|
|
|
+ response = None
|
|
|
if self.state == InstanceState.STOPPED:
|
|
if self.state == InstanceState.STOPPED:
|
|
|
- (self._provider
|
|
|
|
|
- .gce_compute
|
|
|
|
|
- .instances()
|
|
|
|
|
- .start(project=self._provider.project_name,
|
|
|
|
|
- zone=self._provider.default_zone,
|
|
|
|
|
- instance=self.name)
|
|
|
|
|
- .execute())
|
|
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .instances()
|
|
|
|
|
+ .start(project=self._provider.project_name,
|
|
|
|
|
+ zone=self.zone_name,
|
|
|
|
|
+ instance=self.name)
|
|
|
|
|
+ .execute())
|
|
|
else:
|
|
else:
|
|
|
- (self._provider
|
|
|
|
|
- .gce_compute
|
|
|
|
|
- .instances()
|
|
|
|
|
- .reset(project=self._provider.project_name,
|
|
|
|
|
- zone=self._provider.default_zone,
|
|
|
|
|
- instance=self.name)
|
|
|
|
|
- .execute())
|
|
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .instances()
|
|
|
|
|
+ .reset(project=self._provider.project_name,
|
|
|
|
|
+ zone=self.zone_name,
|
|
|
|
|
+ instance=self.name)
|
|
|
|
|
+ .execute())
|
|
|
|
|
+ self._provider.wait_for_operation(response, zone=self.zone_name)
|
|
|
|
|
|
|
|
def delete(self):
|
|
def delete(self):
|
|
|
"""
|
|
"""
|
|
|
Permanently terminate this instance.
|
|
Permanently terminate this instance.
|
|
|
"""
|
|
"""
|
|
|
- (self._provider
|
|
|
|
|
- .gce_compute
|
|
|
|
|
- .instances()
|
|
|
|
|
- .delete(project=self._provider.project_name,
|
|
|
|
|
- zone=self._provider.default_zone,
|
|
|
|
|
- instance=self.name)
|
|
|
|
|
- .execute())
|
|
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .instances()
|
|
|
|
|
+ .delete(project=self._provider.project_name,
|
|
|
|
|
+ zone=self.zone_name,
|
|
|
|
|
+ instance=self.name)
|
|
|
|
|
+ .execute())
|
|
|
|
|
+ self._provider.wait_for_operation(response, zone=self.zone_name)
|
|
|
|
|
|
|
|
def stop(self):
|
|
def stop(self):
|
|
|
"""
|
|
"""
|
|
|
Stop this instance.
|
|
Stop this instance.
|
|
|
"""
|
|
"""
|
|
|
- (self._provider
|
|
|
|
|
- .gce_compute
|
|
|
|
|
- .instances()
|
|
|
|
|
- .stop(project=self._provider.project_name,
|
|
|
|
|
- zone=self._provider.default_zone,
|
|
|
|
|
- instance=self.name)
|
|
|
|
|
- .execute())
|
|
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .instances()
|
|
|
|
|
+ .stop(project=self._provider.project_name,
|
|
|
|
|
+ zone=self.zone_name,
|
|
|
|
|
+ instance=self.name)
|
|
|
|
|
+ .execute())
|
|
|
|
|
+ self._provider.wait_for_operation(response, zone=self.zone_name)
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def image_id(self):
|
|
def image_id(self):
|
|
@@ -907,6 +888,10 @@ class GCEInstance(BaseInstance):
|
|
|
"""
|
|
"""
|
|
|
return self._gce_instance.get('zone')
|
|
return self._gce_instance.get('zone')
|
|
|
|
|
|
|
|
|
|
+ @property
|
|
|
|
|
+ def zone_name(self):
|
|
|
|
|
+ return self._provider.parse_url(self.zone_id).parameters['zone']
|
|
|
|
|
+
|
|
|
@property
|
|
@property
|
|
|
def vm_firewalls(self):
|
|
def vm_firewalls(self):
|
|
|
"""
|
|
"""
|
|
@@ -943,6 +928,16 @@ class GCEInstance(BaseInstance):
|
|
|
"""
|
|
"""
|
|
|
return self._provider.security.key_pairs.name
|
|
return self._provider.security.key_pairs.name
|
|
|
|
|
|
|
|
|
|
+ @property
|
|
|
|
|
+ def inet_gateway(self):
|
|
|
|
|
+ if self._inet_gateway:
|
|
|
|
|
+ return self._inet_gateway
|
|
|
|
|
+ network_url = self._gce_instance.get('networkInterfaces')[0].get(
|
|
|
|
|
+ 'network')
|
|
|
|
|
+ network = self._provider.networking.networks.get(network_url)
|
|
|
|
|
+ self._inet_gateway = network.gateways.get_or_create_inet_gateway()
|
|
|
|
|
+ return self._inet_gateway
|
|
|
|
|
+
|
|
|
def create_image(self, name):
|
|
def create_image(self, name):
|
|
|
"""
|
|
"""
|
|
|
Create a new image based on this instance.
|
|
Create a new image based on this instance.
|
|
@@ -961,10 +956,12 @@ class GCEInstance(BaseInstance):
|
|
|
.gce_compute
|
|
.gce_compute
|
|
|
.images()
|
|
.images()
|
|
|
.insert(project=self._provider.project_name,
|
|
.insert(project=self._provider.project_name,
|
|
|
- body=image_body)
|
|
|
|
|
|
|
+ body=image_body,
|
|
|
|
|
+ forceCreate=True)
|
|
|
.execute())
|
|
.execute())
|
|
|
self._provider.wait_for_operation(operation)
|
|
self._provider.wait_for_operation(operation)
|
|
|
- return
|
|
|
|
|
|
|
+ img = self._provider.get_resource('images', name)
|
|
|
|
|
+ return GCEMachineImage(self._provider, img) if img else None
|
|
|
cb.log.error('Failed to create image: no boot disk found.')
|
|
cb.log.error('Failed to create image: no boot disk found.')
|
|
|
|
|
|
|
|
def _get_existing_target_instance(self):
|
|
def _get_existing_target_instance(self):
|
|
@@ -973,12 +970,11 @@ class GCEInstance(BaseInstance):
|
|
|
|
|
|
|
|
If there is no target instance for this instance, return None.
|
|
If there is no target instance for this instance, return None.
|
|
|
"""
|
|
"""
|
|
|
- self_url = self._provider.parse_url(self._gce_instance['selfLink'])
|
|
|
|
|
try:
|
|
try:
|
|
|
for target_instance in helpers.iter_all(
|
|
for target_instance in helpers.iter_all(
|
|
|
self._provider.gce_compute.targetInstances(),
|
|
self._provider.gce_compute.targetInstances(),
|
|
|
- project=self_url.parameters['project'],
|
|
|
|
|
- zone=self_url.parameters['zone']):
|
|
|
|
|
|
|
+ project=self.name,
|
|
|
|
|
+ zone=self.zone_name):
|
|
|
url = self._provider.parse_url(target_instance['instance'])
|
|
url = self._provider.parse_url(target_instance['instance'])
|
|
|
if url.parameters['instance'] == self.name:
|
|
if url.parameters['instance'] == self.name:
|
|
|
return target_instance
|
|
return target_instance
|
|
@@ -997,19 +993,17 @@ class GCEInstance(BaseInstance):
|
|
|
return existing_target_instance
|
|
return existing_target_instance
|
|
|
|
|
|
|
|
# No targetInstance exists for this instance. Create one.
|
|
# No targetInstance exists for this instance. Create one.
|
|
|
- self_url = self._provider.parse_url(self._gce_instance['selfLink'])
|
|
|
|
|
body = {'name': 'target-instance-{0}'.format(uuid.uuid4()),
|
|
body = {'name': 'target-instance-{0}'.format(uuid.uuid4()),
|
|
|
'instance': self._gce_instance['selfLink']}
|
|
'instance': self._gce_instance['selfLink']}
|
|
|
try:
|
|
try:
|
|
|
response = (self._provider
|
|
response = (self._provider
|
|
|
.gce_compute
|
|
.gce_compute
|
|
|
.targetInstances()
|
|
.targetInstances()
|
|
|
- .insert(project=self_url.parameters['project'],
|
|
|
|
|
- zone=self_url.parameters['zone'],
|
|
|
|
|
|
|
+ .insert(project=self.name,
|
|
|
|
|
+ zone=self.zone_name,
|
|
|
body=body)
|
|
body=body)
|
|
|
.execute())
|
|
.execute())
|
|
|
- self._provider.wait_for_operation(
|
|
|
|
|
- response, zone=self_url.parameters['zone'])
|
|
|
|
|
|
|
+ self._provider.wait_for_operation(response, zone=self.zone_name)
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
cb.log.warning('Exception while inserting a target instance: %s',
|
|
cb.log.warning('Exception while inserting a target instance: %s',
|
|
|
e)
|
|
e)
|
|
@@ -1031,7 +1025,7 @@ class GCEInstance(BaseInstance):
|
|
|
for rule in helpers.iter_all(
|
|
for rule in helpers.iter_all(
|
|
|
self._provider.gce_compute.forwardingRules(),
|
|
self._provider.gce_compute.forwardingRules(),
|
|
|
project=self._provider.project_name,
|
|
project=self._provider.project_name,
|
|
|
- region=ip.region):
|
|
|
|
|
|
|
+ region=ip.region_name):
|
|
|
if rule['IPAddress'] != ip.public_ip:
|
|
if rule['IPAddress'] != ip.public_ip:
|
|
|
continue
|
|
continue
|
|
|
parsed_target_url = self._provider.parse_url(rule['target'])
|
|
parsed_target_url = self._provider.parse_url(rule['target'])
|
|
@@ -1044,11 +1038,12 @@ class GCEInstance(BaseInstance):
|
|
|
.forwardingRules()
|
|
.forwardingRules()
|
|
|
.setTarget(
|
|
.setTarget(
|
|
|
project=self._provider.project_name,
|
|
project=self._provider.project_name,
|
|
|
- region=ip.region,
|
|
|
|
|
|
|
+ region=ip.region_name,
|
|
|
forwardingRule=rule['name'],
|
|
forwardingRule=rule['name'],
|
|
|
body={'target': new_url})
|
|
body={'target': new_url})
|
|
|
.execute())
|
|
.execute())
|
|
|
- self._provider.wait_for_operation(response, region=ip.region)
|
|
|
|
|
|
|
+ self._provider.wait_for_operation(response,
|
|
|
|
|
+ region=ip.region_name)
|
|
|
return True
|
|
return True
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
cb.log.warning(
|
|
cb.log.warning(
|
|
@@ -1072,10 +1067,10 @@ class GCEInstance(BaseInstance):
|
|
|
.gce_compute
|
|
.gce_compute
|
|
|
.forwardingRules()
|
|
.forwardingRules()
|
|
|
.insert(project=self._provider.project_name,
|
|
.insert(project=self._provider.project_name,
|
|
|
- region=ip.region,
|
|
|
|
|
|
|
+ region=ip.region_name,
|
|
|
body=body)
|
|
body=body)
|
|
|
.execute())
|
|
.execute())
|
|
|
- self._provider.wait_for_operation(response, region=ip.region)
|
|
|
|
|
|
|
+ self._provider.wait_for_operation(response, region=ip.region_name)
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
cb.log.warning('Exception while inserting a forwarding rule: %s',
|
|
cb.log.warning('Exception while inserting a forwarding rule: %s',
|
|
|
e)
|
|
e)
|
|
@@ -1093,7 +1088,7 @@ class GCEInstance(BaseInstance):
|
|
|
for rule in helpers.iter_all(
|
|
for rule in helpers.iter_all(
|
|
|
self._provider.gce_compute.forwardingRules(),
|
|
self._provider.gce_compute.forwardingRules(),
|
|
|
project=self._provider.project_name,
|
|
project=self._provider.project_name,
|
|
|
- region=ip.region):
|
|
|
|
|
|
|
+ region=ip.region_name):
|
|
|
if rule['IPAddress'] != ip.public_ip:
|
|
if rule['IPAddress'] != ip.public_ip:
|
|
|
continue
|
|
continue
|
|
|
parsed_target_url = self._provider.parse_url(rule['target'])
|
|
parsed_target_url = self._provider.parse_url(rule['target'])
|
|
@@ -1109,10 +1104,11 @@ class GCEInstance(BaseInstance):
|
|
|
.forwardingRules()
|
|
.forwardingRules()
|
|
|
.delete(
|
|
.delete(
|
|
|
project=self._provider.project_name,
|
|
project=self._provider.project_name,
|
|
|
- region=ip.region,
|
|
|
|
|
|
|
+ region=ip.region_name,
|
|
|
forwardingRule=rule['name'])
|
|
forwardingRule=rule['name'])
|
|
|
.execute())
|
|
.execute())
|
|
|
- self._provider.wait_for_operation(response, region=ip.region)
|
|
|
|
|
|
|
+ self._provider.wait_for_operation(response,
|
|
|
|
|
+ region=ip.region_name)
|
|
|
return True
|
|
return True
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
cb.log.warning(
|
|
cb.log.warning(
|
|
@@ -1124,7 +1120,7 @@ class GCEInstance(BaseInstance):
|
|
|
"""
|
|
"""
|
|
|
Add an elastic IP address to this instance.
|
|
Add an elastic IP address to this instance.
|
|
|
"""
|
|
"""
|
|
|
- for ip in self._provider.networking.floating_ips:
|
|
|
|
|
|
|
+ for ip in self.inet_gateway.floating_ips:
|
|
|
if ip.public_ip == ip_address:
|
|
if ip.public_ip == ip_address:
|
|
|
if ip.in_use():
|
|
if ip.in_use():
|
|
|
if ip.private_ip not in self.private_ips:
|
|
if ip.private_ip not in self.private_ips:
|
|
@@ -1148,7 +1144,7 @@ class GCEInstance(BaseInstance):
|
|
|
"""
|
|
"""
|
|
|
Remove a elastic IP address from this instance.
|
|
Remove a elastic IP address from this instance.
|
|
|
"""
|
|
"""
|
|
|
- for ip in self._provider.networking.floating_ips:
|
|
|
|
|
|
|
+ for ip in self.inet_gateway.floating_ips:
|
|
|
if ip.public_ip == ip_address:
|
|
if ip.public_ip == ip_address:
|
|
|
if not ip.in_use() or ip.private_ip not in self.private_ips:
|
|
if not ip.in_use() or ip.private_ip not in self.private_ips:
|
|
|
cb.log.warning(
|
|
cb.log.warning(
|
|
@@ -1179,14 +1175,37 @@ class GCEInstance(BaseInstance):
|
|
|
Refreshes the state of this instance by re-querying the cloud provider
|
|
Refreshes the state of this instance by re-querying the cloud provider
|
|
|
for its latest state.
|
|
for its latest state.
|
|
|
"""
|
|
"""
|
|
|
- self_link = self._gce_instance.get('selfLink')
|
|
|
|
|
- self._gce_instance = self._provider.parse_url(self_link).get_resource()
|
|
|
|
|
|
|
+ self._gce_instance = self._provider.get_resource('instances', self.id)
|
|
|
|
|
+ if not self._gce_instance:
|
|
|
|
|
+ self._gce_instance = {'status': 'UNKNOWN'}
|
|
|
|
|
|
|
|
def add_vm_firewall(self, sg):
|
|
def add_vm_firewall(self, sg):
|
|
|
- raise NotImplementedError('To be implemented.')
|
|
|
|
|
|
|
+ tag = sg.name if isinstance(sg, GCEVMFirewall) else sg
|
|
|
|
|
+ tags = self._gce_instance.get('tags', {}).get('items', [])
|
|
|
|
|
+ tags.append(tag)
|
|
|
|
|
+ self._set_tags(tags)
|
|
|
|
|
|
|
|
def remove_vm_firewall(self, sg):
|
|
def remove_vm_firewall(self, sg):
|
|
|
- raise NotImplementedError('To be implemented.')
|
|
|
|
|
|
|
+ tag = sg.name if isinstance(sg, GCEVMFirewall) else sg
|
|
|
|
|
+ tags = self._gce_instance.get('tags', {}).get('items', [])
|
|
|
|
|
+ if tag in tags:
|
|
|
|
|
+ tags.remove(tag)
|
|
|
|
|
+ self._set_tags(tags)
|
|
|
|
|
+
|
|
|
|
|
+ def _set_tags(self, tags):
|
|
|
|
|
+ # Refresh to make sure we are using the most recent tags fingerprint.
|
|
|
|
|
+ self.refresh()
|
|
|
|
|
+ fingerprint = self._gce_instance.get('tags', {}).get('fingerprint', '')
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .instances()
|
|
|
|
|
+ .setTags(project=self._provider.project_name,
|
|
|
|
|
+ zone=self.zone_name,
|
|
|
|
|
+ instance=self.name,
|
|
|
|
|
+ body={'items': tags,
|
|
|
|
|
+ 'fingerprint': fingerprint})
|
|
|
|
|
+ .execute())
|
|
|
|
|
+ self._provider.wait_for_operation(response, zone=self.zone_name)
|
|
|
|
|
|
|
|
|
|
|
|
|
class GCENetwork(BaseNetwork):
|
|
class GCENetwork(BaseNetwork):
|
|
@@ -1222,6 +1241,8 @@ class GCENetwork(BaseNetwork):
|
|
|
When a GCP network created by the CloudBridge API, we wait until the
|
|
When a GCP network created by the CloudBridge API, we wait until the
|
|
|
network is ready.
|
|
network is ready.
|
|
|
"""
|
|
"""
|
|
|
|
|
+ if 'status' in self._network and self._network['status'] == 'UNKNOWN':
|
|
|
|
|
+ return NetworkState.UNKNOWN
|
|
|
return NetworkState.AVAILABLE
|
|
return NetworkState.AVAILABLE
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
@@ -1256,8 +1277,9 @@ class GCENetwork(BaseNetwork):
|
|
|
self, cidr_block, name, zone)
|
|
self, cidr_block, name, zone)
|
|
|
|
|
|
|
|
def refresh(self):
|
|
def refresh(self):
|
|
|
- self_link = self._network.get('selfLink')
|
|
|
|
|
- self._network = self._provider.parse_url(self_link).get_resource()
|
|
|
|
|
|
|
+ self._network = self._provider.get_resource('networks', self.id)
|
|
|
|
|
+ if not self._network:
|
|
|
|
|
+ self._network = {'status': 'UNKNOWN'}
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def gateways(self):
|
|
def gateways(self):
|
|
@@ -1270,30 +1292,21 @@ class GCEFloatingIPContainer(BaseFloatingIPContainer):
|
|
|
super(GCEFloatingIPContainer, self).__init__(provider, gateway)
|
|
super(GCEFloatingIPContainer, self).__init__(provider, gateway)
|
|
|
|
|
|
|
|
def get(self, floating_ip_id):
|
|
def get(self, floating_ip_id):
|
|
|
- try:
|
|
|
|
|
- response = (self.provider
|
|
|
|
|
- .gce_compute
|
|
|
|
|
- .addresses()
|
|
|
|
|
- .get(project=self.provider.project_name,
|
|
|
|
|
- region=self.provider.region_name)
|
|
|
|
|
- .execute())
|
|
|
|
|
- return GCEFloatingIP(self.provider, response)
|
|
|
|
|
- except googleapiclient.errors.HttpError as http_error:
|
|
|
|
|
- cb.log.warning('googleapiclient.errors.HttpError: %s', http_error)
|
|
|
|
|
- return None
|
|
|
|
|
|
|
+ fip = self._provider.get_resource('addresses', floating_ip_id)
|
|
|
|
|
+ return GCEFloatingIP(self._provider, fip) if fip else None
|
|
|
|
|
|
|
|
def list(self, limit=None, marker=None):
|
|
def list(self, limit=None, marker=None):
|
|
|
max_result = limit if limit is not None and limit < 500 else 500
|
|
max_result = limit if limit is not None and limit < 500 else 500
|
|
|
try:
|
|
try:
|
|
|
- response = (self.provider
|
|
|
|
|
|
|
+ response = (self._provider
|
|
|
.gce_compute
|
|
.gce_compute
|
|
|
.addresses()
|
|
.addresses()
|
|
|
- .list(project=self.provider.project_name,
|
|
|
|
|
- region=self.provider.region_name,
|
|
|
|
|
|
|
+ .list(project=self._provider.project_name,
|
|
|
|
|
+ region=self._provider.region_name,
|
|
|
maxResults=max_result,
|
|
maxResults=max_result,
|
|
|
pageToken=marker)
|
|
pageToken=marker)
|
|
|
.execute())
|
|
.execute())
|
|
|
- ips = [GCEFloatingIP(self.provider, ip)
|
|
|
|
|
|
|
+ ips = [GCEFloatingIP(self._provider, ip)
|
|
|
for ip in response.get('items', [])]
|
|
for ip in response.get('items', [])]
|
|
|
if len(ips) > max_result:
|
|
if len(ips) > max_result:
|
|
|
cb.log.warning('Expected at most %d results; got %d',
|
|
cb.log.warning('Expected at most %d results; got %d',
|
|
@@ -1306,19 +1319,19 @@ class GCEFloatingIPContainer(BaseFloatingIPContainer):
|
|
|
return None
|
|
return None
|
|
|
|
|
|
|
|
def create(self):
|
|
def create(self):
|
|
|
- region = self.provider.region_name
|
|
|
|
|
|
|
+ region_name = self._provider.region_name
|
|
|
ip_name = 'ip-{0}'.format(uuid.uuid4())
|
|
ip_name = 'ip-{0}'.format(uuid.uuid4())
|
|
|
try:
|
|
try:
|
|
|
- response = (self.provider
|
|
|
|
|
|
|
+ response = (self._provider
|
|
|
.gce_compute
|
|
.gce_compute
|
|
|
.addresses()
|
|
.addresses()
|
|
|
- .insert(project=self.provider.project_name,
|
|
|
|
|
- region=region,
|
|
|
|
|
|
|
+ .insert(project=self._provider.project_name,
|
|
|
|
|
+ region=region_name,
|
|
|
body={'name': ip_name})
|
|
body={'name': ip_name})
|
|
|
.execute())
|
|
.execute())
|
|
|
if 'error' in response:
|
|
if 'error' in response:
|
|
|
return None
|
|
return None
|
|
|
- self.provider.wait_for_operation(response, region=region)
|
|
|
|
|
|
|
+ self._provider.wait_for_operation(response, region=region_name)
|
|
|
return self.get(ip_name)
|
|
return self.get(ip_name)
|
|
|
except googleapiclient.errors.HttpError as http_error:
|
|
except googleapiclient.errors.HttpError as http_error:
|
|
|
cb.log.warning('googleapiclient.errors.HttpError: %s', http_error)
|
|
cb.log.warning('googleapiclient.errors.HttpError: %s', http_error)
|
|
@@ -1336,7 +1349,7 @@ class GCEFloatingIP(BaseFloatingIP):
|
|
|
# global IPs can be forwarded only to load balancing resources, not to
|
|
# global IPs can be forwarded only to load balancing resources, not to
|
|
|
# a specific instance. Find out the region to which the IP belongs.
|
|
# a specific instance. Find out the region to which the IP belongs.
|
|
|
url = provider.parse_url(self._ip['region'])
|
|
url = provider.parse_url(self._ip['region'])
|
|
|
- self._region = url.parameters['region']
|
|
|
|
|
|
|
+ self._region_name = url.parameters['region']
|
|
|
|
|
|
|
|
# Check if the address is used by a resource.
|
|
# Check if the address is used by a resource.
|
|
|
self._rule = None
|
|
self._rule = None
|
|
@@ -1368,8 +1381,8 @@ class GCEFloatingIP(BaseFloatingIP):
|
|
|
return self._ip['selfLink']
|
|
return self._ip['selfLink']
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
- def region(self):
|
|
|
|
|
- return self._region
|
|
|
|
|
|
|
+ def region_name(self):
|
|
|
|
|
+ return self._region_name
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def public_ip(self):
|
|
def public_ip(self):
|
|
@@ -1393,23 +1406,26 @@ class GCEFloatingIP(BaseFloatingIP):
|
|
|
.gce_compute
|
|
.gce_compute
|
|
|
.forwardingRules()
|
|
.forwardingRules()
|
|
|
.delete(project=project_name,
|
|
.delete(project=project_name,
|
|
|
- region=self._region,
|
|
|
|
|
|
|
+ region=self._region_name,
|
|
|
forwardingRule=self._rule['name'])
|
|
forwardingRule=self._rule['name'])
|
|
|
.execute())
|
|
.execute())
|
|
|
- self._provider.wait_for_operation(response, region=self._region)
|
|
|
|
|
|
|
+ self._provider.wait_for_operation(response,
|
|
|
|
|
+ region=self._region_name)
|
|
|
|
|
|
|
|
# Release the address.
|
|
# Release the address.
|
|
|
response = (self._provider
|
|
response = (self._provider
|
|
|
.gce_compute
|
|
.gce_compute
|
|
|
.addresses()
|
|
.addresses()
|
|
|
.delete(project=project_name,
|
|
.delete(project=project_name,
|
|
|
- region=self._region,
|
|
|
|
|
|
|
+ region=self._region_name,
|
|
|
address=self._ip['name'])
|
|
address=self._ip['name'])
|
|
|
.execute())
|
|
.execute())
|
|
|
- self._provider.wait_for_operation(response, region=self._region)
|
|
|
|
|
|
|
+ self._provider.wait_for_operation(response, region=self._region_name)
|
|
|
|
|
|
|
|
def refresh(self):
|
|
def refresh(self):
|
|
|
- pass
|
|
|
|
|
|
|
+ self._ip = self._provider.get_resource('addresses', self.id)
|
|
|
|
|
+ if not self._ip:
|
|
|
|
|
+ self._ip = {'status': 'UNKNOWN'}
|
|
|
|
|
|
|
|
|
|
|
|
|
class GCERouter(BaseRouter):
|
|
class GCERouter(BaseRouter):
|
|
@@ -1426,12 +1442,22 @@ class GCERouter(BaseRouter):
|
|
|
def name(self):
|
|
def name(self):
|
|
|
return self._router['name']
|
|
return self._router['name']
|
|
|
|
|
|
|
|
|
|
+ @property
|
|
|
|
|
+ def region_name(self):
|
|
|
|
|
+ parsed_url = self._provider.parse_url(self.id)
|
|
|
|
|
+ return parsed_url.parameters['region']
|
|
|
|
|
+
|
|
|
def refresh(self):
|
|
def refresh(self):
|
|
|
- parsed_url = self._provider.parse_url(self._router['selfLink'])
|
|
|
|
|
- self._router = parsed_url.get_resource()
|
|
|
|
|
|
|
+ self._router = self._provider.get_resource('routers', self.id)
|
|
|
|
|
+ if not self._router:
|
|
|
|
|
+ self._router = {'status': 'UNKNOWN'}
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def state(self):
|
|
def state(self):
|
|
|
|
|
+ # If the router info is refreshed after it is deleted, its status will
|
|
|
|
|
+ # be UNKNOWN.
|
|
|
|
|
+ if 'status' in self._router and self._router['status'] == 'UNKNOWN':
|
|
|
|
|
+ return RouterState.UNKNOWN
|
|
|
# GCE routers are always attached to a network.
|
|
# GCE routers are always attached to a network.
|
|
|
return RouterState.ATTACHED
|
|
return RouterState.ATTACHED
|
|
|
|
|
|
|
@@ -1446,25 +1472,26 @@ class GCERouter(BaseRouter):
|
|
|
.gce_compute
|
|
.gce_compute
|
|
|
.routers()
|
|
.routers()
|
|
|
.delete(project=self._provider.project_name,
|
|
.delete(project=self._provider.project_name,
|
|
|
- region=self._router['region'],
|
|
|
|
|
- router=self._router['name'])
|
|
|
|
|
|
|
+ region=self.region_name,
|
|
|
|
|
+ router=self.name)
|
|
|
.execute())
|
|
.execute())
|
|
|
- self._provider.wait_for_operation(response,
|
|
|
|
|
- region=self._router['region'])
|
|
|
|
|
|
|
+ self._provider.wait_for_operation(response, region=self.region_name)
|
|
|
|
|
|
|
|
- def attach_network(self, network_id):
|
|
|
|
|
- if network_id == self.network_id:
|
|
|
|
|
|
|
+ def attach_subnet(self, subnet):
|
|
|
|
|
+ if not isinstance(subnet, GCESubnet):
|
|
|
|
|
+ subnet = self._provider.networking.subnets.get(subnet)
|
|
|
|
|
+ if subnet.network_id == self.network_id:
|
|
|
return
|
|
return
|
|
|
cb.log.warning('GCE routers should be attached at creation time')
|
|
cb.log.warning('GCE routers should be attached at creation time')
|
|
|
|
|
|
|
|
- def detach_network(self, network_id):
|
|
|
|
|
|
|
+ def detach_subnet(self, network_id):
|
|
|
cb.log.warning('GCE routers are always attached')
|
|
cb.log.warning('GCE routers are always attached')
|
|
|
|
|
|
|
|
- def add_route(self, subnet_id):
|
|
|
|
|
- cb.log.warning('Not implemented')
|
|
|
|
|
|
|
+ def attach_gateway(self, gateway):
|
|
|
|
|
+ pass
|
|
|
|
|
|
|
|
- def remove_route(self, subnet_id):
|
|
|
|
|
- cb.log.warning('Not implemented')
|
|
|
|
|
|
|
+ def detach_gateway(self, gateway):
|
|
|
|
|
+ pass
|
|
|
|
|
|
|
|
|
|
|
|
|
class GCEGatewayContainer(BaseGatewayContainer):
|
|
class GCEGatewayContainer(BaseGatewayContainer):
|
|
@@ -1479,8 +1506,7 @@ class GCEGatewayContainer(BaseGatewayContainer):
|
|
|
GCEGatewayContainer._DEFAULT_GATEWAY_NAME),
|
|
GCEGatewayContainer._DEFAULT_GATEWAY_NAME),
|
|
|
'name': GCEGatewayContainer._DEFAULT_GATEWAY_NAME})
|
|
'name': GCEGatewayContainer._DEFAULT_GATEWAY_NAME})
|
|
|
|
|
|
|
|
- def get_or_create_inet_gateway(self, name):
|
|
|
|
|
- GCEInternetGateway.assert_valid_resource_name(name)
|
|
|
|
|
|
|
+ def get_or_create_inet_gateway(self, name=None):
|
|
|
return self._default_internet_gateway
|
|
return self._default_internet_gateway
|
|
|
|
|
|
|
|
def delete(self, gateway):
|
|
def delete(self, gateway):
|
|
@@ -1526,7 +1552,7 @@ class GCEInternetGateway(BaseInternetGateway):
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def floating_ips(self):
|
|
def floating_ips(self):
|
|
|
- return self._fips_container
|
|
|
|
|
|
|
+ return self._fip_container
|
|
|
|
|
|
|
|
|
|
|
|
|
class GCESubnet(BaseSubnet):
|
|
class GCESubnet(BaseSubnet):
|
|
@@ -1559,38 +1585,43 @@ class GCESubnet(BaseSubnet):
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def network_id(self):
|
|
def network_id(self):
|
|
|
- return self._provider.parse_url(
|
|
|
|
|
- self.network_url).get_resource()['selfLink']
|
|
|
|
|
|
|
+ return self.network_url
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def region(self):
|
|
def region(self):
|
|
|
return self._subnet['region']
|
|
return self._subnet['region']
|
|
|
|
|
|
|
|
|
|
+ @property
|
|
|
|
|
+ def region_name(self):
|
|
|
|
|
+ parsed_url = self.provider.parse_url(self.id)
|
|
|
|
|
+ return parsed_url.parameters['region']
|
|
|
|
|
+
|
|
|
@property
|
|
@property
|
|
|
def zone(self):
|
|
def zone(self):
|
|
|
return None
|
|
return None
|
|
|
|
|
|
|
|
- @property
|
|
|
|
|
def delete(self):
|
|
def delete(self):
|
|
|
return self._provider.networking.subnets.delete(self)
|
|
return self._provider.networking.subnets.delete(self)
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def state(self):
|
|
def state(self):
|
|
|
- return SubnetState.AVAILABEL
|
|
|
|
|
|
|
+ if 'status' in self._subnet and self._subnet['status'] == 'UNKNOWN':
|
|
|
|
|
+ return SubnetState.UNKNOWN
|
|
|
|
|
+ return SubnetState.AVAILABLE
|
|
|
|
|
|
|
|
def refresh(self):
|
|
def refresh(self):
|
|
|
- self_link = self._subnet.get('selfLink')
|
|
|
|
|
- self._subnet = self._provider.parse_url(self_link).get_resource()
|
|
|
|
|
|
|
+ self._subnet = self._provider.get_resource('subnetworks', self.id)
|
|
|
|
|
+ if not self._subnet:
|
|
|
|
|
+ self._subnet = {'status': 'UNKNOWN'}
|
|
|
|
|
|
|
|
|
|
|
|
|
class GCEVolume(BaseVolume):
|
|
class GCEVolume(BaseVolume):
|
|
|
|
|
|
|
|
VOLUME_STATE_MAP = {
|
|
VOLUME_STATE_MAP = {
|
|
|
- 'RESTORING': VolumeState.CONFIGURING,
|
|
|
|
|
- 'PENDING': VolumeState.CONFIGURING,
|
|
|
|
|
|
|
+ 'CREATING': VolumeState.CONFIGURING,
|
|
|
|
|
+ 'FAILED': VolumeState.ERROR,
|
|
|
'READY': VolumeState.AVAILABLE,
|
|
'READY': VolumeState.AVAILABLE,
|
|
|
- 'DONE': VolumeState.AVAILABLE,
|
|
|
|
|
- 'RUNNING': VolumeState.IN_USE,
|
|
|
|
|
|
|
+ 'RESTORING': VolumeState.CONFIGURING,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
def __init__(self, provider, volume):
|
|
def __init__(self, provider, volume):
|
|
@@ -1639,7 +1670,7 @@ class GCEVolume(BaseVolume):
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def size(self):
|
|
def size(self):
|
|
|
- return self._volume.get('sizeGb')
|
|
|
|
|
|
|
+ return int(self._volume.get('sizeGb'))
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def create_time(self):
|
|
def create_time(self):
|
|
@@ -1691,17 +1722,16 @@ class GCEVolume(BaseVolume):
|
|
|
"""
|
|
"""
|
|
|
attach_disk_body = {
|
|
attach_disk_body = {
|
|
|
"source": self.id,
|
|
"source": self.id,
|
|
|
- "deviceName": device,
|
|
|
|
|
|
|
+ "deviceName": device.split('/')[-1],
|
|
|
}
|
|
}
|
|
|
- instance_name = instance.name if isinstance(
|
|
|
|
|
- instance,
|
|
|
|
|
- GCEInstance) else instance
|
|
|
|
|
|
|
+ if not isinstance(instance, GCEInstance):
|
|
|
|
|
+ instance = self._provider.get_resource('instances', instance)
|
|
|
(self._provider
|
|
(self._provider
|
|
|
.gce_compute
|
|
.gce_compute
|
|
|
.instances()
|
|
.instances()
|
|
|
.attachDisk(project=self._provider.project_name,
|
|
.attachDisk(project=self._provider.project_name,
|
|
|
- zone=self._provider.default_zone,
|
|
|
|
|
- instance=instance_name,
|
|
|
|
|
|
|
+ zone=instance.zone_name,
|
|
|
|
|
+ instance=instance.name,
|
|
|
body=attach_disk_body)
|
|
body=attach_disk_body)
|
|
|
.execute())
|
|
.execute())
|
|
|
|
|
|
|
@@ -1754,6 +1784,8 @@ class GCEVolume(BaseVolume):
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def state(self):
|
|
def state(self):
|
|
|
|
|
+ if len(self._volume.get('users', [])) > 0:
|
|
|
|
|
+ return VolumeState.IN_USE
|
|
|
return GCEVolume.VOLUME_STATE_MAP.get(
|
|
return GCEVolume.VOLUME_STATE_MAP.get(
|
|
|
self._volume.get('status'), VolumeState.UNKNOWN)
|
|
self._volume.get('status'), VolumeState.UNKNOWN)
|
|
|
|
|
|
|
@@ -1762,8 +1794,9 @@ class GCEVolume(BaseVolume):
|
|
|
Refreshes the state of this volume by re-querying the cloud provider
|
|
Refreshes the state of this volume by re-querying the cloud provider
|
|
|
for its latest state.
|
|
for its latest state.
|
|
|
"""
|
|
"""
|
|
|
- self_link = self._volume.get('selfLink')
|
|
|
|
|
- self._volume = self._provider.parse_url(self_link).get_resource()
|
|
|
|
|
|
|
+ self._volume = self._provider.get_resource('disks', self.id)
|
|
|
|
|
+ if not self._volume:
|
|
|
|
|
+ self._volume = {'status': 'UNKNOWN'}
|
|
|
|
|
|
|
|
|
|
|
|
|
class GCESnapshot(BaseSnapshot):
|
|
class GCESnapshot(BaseSnapshot):
|
|
@@ -1798,7 +1831,7 @@ class GCESnapshot(BaseSnapshot):
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def size(self):
|
|
def size(self):
|
|
|
- return self._snapshot.get('diskSizeGb')
|
|
|
|
|
|
|
+ return int(self._snapshot.get('diskSizeGb'))
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def volume_id(self):
|
|
def volume_id(self):
|
|
@@ -1818,8 +1851,9 @@ class GCESnapshot(BaseSnapshot):
|
|
|
Refreshes the state of this snapshot by re-querying the cloud provider
|
|
Refreshes the state of this snapshot by re-querying the cloud provider
|
|
|
for its latest state.
|
|
for its latest state.
|
|
|
"""
|
|
"""
|
|
|
- self_link = self._snapshot.get('selfLink')
|
|
|
|
|
- self._snapshot = self._provider.parse_url(self_link).get_resource()
|
|
|
|
|
|
|
+ self._snapshot = self._provider.get_resource('snapshots', self.id)
|
|
|
|
|
+ if not self._snapshot:
|
|
|
|
|
+ self._snapshot = {'status': 'UNKNOWN'}
|
|
|
|
|
|
|
|
def delete(self):
|
|
def delete(self):
|
|
|
"""
|
|
"""
|
|
@@ -1844,8 +1878,11 @@ class GCESnapshot(BaseSnapshot):
|
|
|
'pd-ssd'.
|
|
'pd-ssd'.
|
|
|
iops: Not supported by GCE.
|
|
iops: Not supported by GCE.
|
|
|
"""
|
|
"""
|
|
|
|
|
+ zone_name = placement
|
|
|
|
|
+ if isinstance(placement, GCEPlacementZone):
|
|
|
|
|
+ zone_name = placement.name
|
|
|
vol_type = 'zones/{0}/diskTypes/{1}'.format(
|
|
vol_type = 'zones/{0}/diskTypes/{1}'.format(
|
|
|
- placement,
|
|
|
|
|
|
|
+ zone_name,
|
|
|
'pd-standard' if (volume_type != 'pd-standard' or
|
|
'pd-standard' if (volume_type != 'pd-standard' or
|
|
|
volume_type != 'pd-ssd') else volume_type)
|
|
volume_type != 'pd-ssd') else volume_type)
|
|
|
disk_body = {
|
|
disk_body = {
|
|
@@ -1858,7 +1895,7 @@ class GCESnapshot(BaseSnapshot):
|
|
|
.gce_compute
|
|
.gce_compute
|
|
|
.disks()
|
|
.disks()
|
|
|
.insert(project=self._provider.project_name,
|
|
.insert(project=self._provider.project_name,
|
|
|
- zone=placement,
|
|
|
|
|
|
|
+ zone=zone_name,
|
|
|
body=disk_body)
|
|
body=disk_body)
|
|
|
.execute())
|
|
.execute())
|
|
|
return self._provider.storage.volumes.get(
|
|
return self._provider.storage.volumes.get(
|
|
@@ -1882,7 +1919,7 @@ class GCSObject(BaseBucketObject):
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def size(self):
|
|
def size(self):
|
|
|
- return self._obj['size']
|
|
|
|
|
|
|
+ return int(self._obj['size'])
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def last_modified(self):
|
|
def last_modified(self):
|
|
@@ -1890,7 +1927,7 @@ class GCSObject(BaseBucketObject):
|
|
|
|
|
|
|
|
def iter_content(self):
|
|
def iter_content(self):
|
|
|
return io.BytesIO(self._provider
|
|
return io.BytesIO(self._provider
|
|
|
- .gcp_storage
|
|
|
|
|
|
|
+ .gcs_storage
|
|
|
.objects()
|
|
.objects()
|
|
|
.get_media(bucket=self._obj['bucket'],
|
|
.get_media(bucket=self._obj['bucket'],
|
|
|
object=self.name)
|
|
object=self.name)
|
|
@@ -1921,7 +1958,7 @@ class GCSObject(BaseBucketObject):
|
|
|
|
|
|
|
|
def delete(self):
|
|
def delete(self):
|
|
|
(self._provider
|
|
(self._provider
|
|
|
- .gcp_storage
|
|
|
|
|
|
|
+ .gcs_storage
|
|
|
.objects()
|
|
.objects()
|
|
|
.delete(bucket=self._obj['bucket'], object=self.name)
|
|
.delete(bucket=self._obj['bucket'], object=self.name)
|
|
|
.execute())
|
|
.execute())
|
|
@@ -1930,39 +1967,18 @@ class GCSObject(BaseBucketObject):
|
|
|
return self._obj['mediaLink']
|
|
return self._obj['mediaLink']
|
|
|
|
|
|
|
|
|
|
|
|
|
-class GCSBucket(BaseBucket):
|
|
|
|
|
|
|
+class GCSBucketContainer(BaseBucketContainer):
|
|
|
|
|
|
|
|
def __init__(self, provider, bucket):
|
|
def __init__(self, provider, bucket):
|
|
|
- super(GCSBucket, self).__init__(provider)
|
|
|
|
|
- self._bucket = bucket
|
|
|
|
|
-
|
|
|
|
|
- @property
|
|
|
|
|
- def id(self):
|
|
|
|
|
- return self._bucket['selfLink']
|
|
|
|
|
-
|
|
|
|
|
- @property
|
|
|
|
|
- def name(self):
|
|
|
|
|
- """
|
|
|
|
|
- Get this bucket's name.
|
|
|
|
|
- """
|
|
|
|
|
- return self._bucket['name']
|
|
|
|
|
|
|
+ super(GCSBucketContainer, self).__init__(provider, bucket)
|
|
|
|
|
|
|
|
def get(self, name):
|
|
def get(self, name):
|
|
|
"""
|
|
"""
|
|
|
Retrieve a given object from this bucket.
|
|
Retrieve a given object from this bucket.
|
|
|
"""
|
|
"""
|
|
|
- try:
|
|
|
|
|
- response = (self._provider
|
|
|
|
|
- .gcp_storage
|
|
|
|
|
- .objects()
|
|
|
|
|
- .get(bucket=self.name, object=name)
|
|
|
|
|
- .execute())
|
|
|
|
|
- if 'error' in response:
|
|
|
|
|
- return None
|
|
|
|
|
- return GCSObject(self._provider, self, response)
|
|
|
|
|
- except googleapiclient.errors.HttpError as http_error:
|
|
|
|
|
- cb.log.warning('googleapiclient.errors.HttpError: %s', http_error)
|
|
|
|
|
- return None
|
|
|
|
|
|
|
+ obj = self._provider.get_resource('objects', name,
|
|
|
|
|
+ bucket=self.bucket.name)
|
|
|
|
|
+ return GCSObject(self._provider, self.bucket, obj) if obj else None
|
|
|
|
|
|
|
|
def list(self, limit=None, marker=None, prefix=None):
|
|
def list(self, limit=None, marker=None, prefix=None):
|
|
|
"""
|
|
"""
|
|
@@ -1971,9 +1987,9 @@ class GCSBucket(BaseBucket):
|
|
|
max_result = limit if limit is not None and limit < 500 else 500
|
|
max_result = limit if limit is not None and limit < 500 else 500
|
|
|
try:
|
|
try:
|
|
|
response = (self._provider
|
|
response = (self._provider
|
|
|
- .gcp_storage
|
|
|
|
|
|
|
+ .gcs_storage
|
|
|
.objects()
|
|
.objects()
|
|
|
- .list(bucket=self.name,
|
|
|
|
|
|
|
+ .list(bucket=self.bucket.name,
|
|
|
prefix=prefix if prefix else '',
|
|
prefix=prefix if prefix else '',
|
|
|
maxResults=max_result,
|
|
maxResults=max_result,
|
|
|
pageToken=marker)
|
|
pageToken=marker)
|
|
@@ -1982,7 +1998,7 @@ class GCSBucket(BaseBucket):
|
|
|
return ServerPagedResultList(False, None, False, data=[])
|
|
return ServerPagedResultList(False, None, False, data=[])
|
|
|
objects = []
|
|
objects = []
|
|
|
for obj in response.get('items', []):
|
|
for obj in response.get('items', []):
|
|
|
- objects.append(GCSObject(self._provider, self, obj))
|
|
|
|
|
|
|
+ objects.append(GCSObject(self._provider, self.bucket, obj))
|
|
|
if len(objects) > max_result:
|
|
if len(objects) > max_result:
|
|
|
cb.log.warning('Expected at most %d results; got %d',
|
|
cb.log.warning('Expected at most %d results; got %d',
|
|
|
max_result, len(objects))
|
|
max_result, len(objects))
|
|
@@ -1993,12 +2009,45 @@ class GCSBucket(BaseBucket):
|
|
|
cb.log.warning('googleapiclient.errors.HttpError: %s', http_error)
|
|
cb.log.warning('googleapiclient.errors.HttpError: %s', http_error)
|
|
|
return ServerPagedResultList(False, None, False, data=[])
|
|
return ServerPagedResultList(False, None, False, data=[])
|
|
|
|
|
|
|
|
|
|
+ def find(self, **kwargs):
|
|
|
|
|
+ obj_list = self.list()
|
|
|
|
|
+ filters = ['name']
|
|
|
|
|
+ matches = cb_helpers.generic_find(filters, kwargs, obj_list)
|
|
|
|
|
+ return ClientPagedResultList(self._provider, list(matches),
|
|
|
|
|
+ limit=None, marker=None)
|
|
|
|
|
+
|
|
|
|
|
+ def create(self, name):
|
|
|
|
|
+ return self.bucket.create_object(name)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class GCSBucket(BaseBucket):
|
|
|
|
|
+
|
|
|
|
|
+ def __init__(self, provider, bucket):
|
|
|
|
|
+ super(GCSBucket, self).__init__(provider)
|
|
|
|
|
+ self._bucket = bucket
|
|
|
|
|
+ self._object_container = GCSBucketContainer(provider, self)
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def id(self):
|
|
|
|
|
+ return self._bucket['selfLink']
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def name(self):
|
|
|
|
|
+ """
|
|
|
|
|
+ Get this bucket's name.
|
|
|
|
|
+ """
|
|
|
|
|
+ return self._bucket['name']
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def objects(self):
|
|
|
|
|
+ return self._object_container
|
|
|
|
|
+
|
|
|
def delete(self, delete_contents=False):
|
|
def delete(self, delete_contents=False):
|
|
|
"""
|
|
"""
|
|
|
Delete this bucket.
|
|
Delete this bucket.
|
|
|
"""
|
|
"""
|
|
|
(self._provider
|
|
(self._provider
|
|
|
- .gcp_storage
|
|
|
|
|
|
|
+ .gcs_storage
|
|
|
.buckets()
|
|
.buckets()
|
|
|
.delete(bucket=self.name)
|
|
.delete(bucket=self.name)
|
|
|
.execute())
|
|
.execute())
|
|
@@ -2014,10 +2063,9 @@ class GCSBucket(BaseBucket):
|
|
|
return GCSObject(self._provider, self, response) if response else None
|
|
return GCSObject(self._provider, self, response) if response else None
|
|
|
|
|
|
|
|
def create_object_with_media_body(self, name, media_body):
|
|
def create_object_with_media_body(self, name, media_body):
|
|
|
- self.assert_valid_resource_name(name)
|
|
|
|
|
try:
|
|
try:
|
|
|
response = (self._provider
|
|
response = (self._provider
|
|
|
- .gcp_storage
|
|
|
|
|
|
|
+ .gcs_storage
|
|
|
.objects()
|
|
.objects()
|
|
|
.insert(bucket=self.name,
|
|
.insert(bucket=self.name,
|
|
|
body={'name': name},
|
|
body={'name': name},
|