|
@@ -1,7 +1,17 @@
|
|
|
"""
|
|
"""
|
|
|
DataTypes used by this provider
|
|
DataTypes used by this provider
|
|
|
"""
|
|
"""
|
|
|
|
|
+import hashlib
|
|
|
|
|
+import inspect
|
|
|
|
|
+import io
|
|
|
|
|
+import json
|
|
|
|
|
+import re
|
|
|
|
|
+import uuid
|
|
|
|
|
+
|
|
|
|
|
+import cloudbridge as cb
|
|
|
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 BaseBucketObject
|
|
|
from cloudbridge.cloud.base.resources import BaseFloatingIP
|
|
from cloudbridge.cloud.base.resources import BaseFloatingIP
|
|
|
from cloudbridge.cloud.base.resources import BaseInstance
|
|
from cloudbridge.cloud.base.resources import BaseInstance
|
|
|
from cloudbridge.cloud.base.resources import BaseInstanceType
|
|
from cloudbridge.cloud.base.resources import BaseInstanceType
|
|
@@ -10,16 +20,21 @@ from cloudbridge.cloud.base.resources import BaseMachineImage
|
|
|
from cloudbridge.cloud.base.resources import BaseNetwork
|
|
from cloudbridge.cloud.base.resources import BaseNetwork
|
|
|
from cloudbridge.cloud.base.resources import BasePlacementZone
|
|
from cloudbridge.cloud.base.resources import BasePlacementZone
|
|
|
from cloudbridge.cloud.base.resources import BaseRegion
|
|
from cloudbridge.cloud.base.resources import BaseRegion
|
|
|
|
|
+from cloudbridge.cloud.base.resources import BaseRouter
|
|
|
from cloudbridge.cloud.base.resources import BaseSecurityGroup
|
|
from cloudbridge.cloud.base.resources import BaseSecurityGroup
|
|
|
from cloudbridge.cloud.base.resources import BaseSecurityGroupRule
|
|
from cloudbridge.cloud.base.resources import BaseSecurityGroupRule
|
|
|
from cloudbridge.cloud.base.resources import BaseSnapshot
|
|
from cloudbridge.cloud.base.resources import BaseSnapshot
|
|
|
|
|
+from cloudbridge.cloud.base.resources import BaseSubnet
|
|
|
from cloudbridge.cloud.base.resources import BaseVolume
|
|
from cloudbridge.cloud.base.resources import BaseVolume
|
|
|
|
|
+from cloudbridge.cloud.base.resources import ServerPagedResultList
|
|
|
from cloudbridge.cloud.interfaces.resources import InstanceState
|
|
from cloudbridge.cloud.interfaces.resources import InstanceState
|
|
|
from cloudbridge.cloud.interfaces.resources import MachineImageState
|
|
from cloudbridge.cloud.interfaces.resources import MachineImageState
|
|
|
|
|
+from cloudbridge.cloud.interfaces.resources import RouterState
|
|
|
from cloudbridge.cloud.interfaces.resources import SnapshotState
|
|
from cloudbridge.cloud.interfaces.resources import SnapshotState
|
|
|
from cloudbridge.cloud.interfaces.resources import VolumeState
|
|
from cloudbridge.cloud.interfaces.resources import VolumeState
|
|
|
|
|
+from cloudbridge.cloud.providers.gce import helpers
|
|
|
|
|
|
|
|
-import cloudbridge as cb
|
|
|
|
|
|
|
+import googleapiclient
|
|
|
|
|
|
|
|
# Older versions of Python do not have a built-in set data-structure.
|
|
# Older versions of Python do not have a built-in set data-structure.
|
|
|
try:
|
|
try:
|
|
@@ -27,12 +42,6 @@ try:
|
|
|
except NameError:
|
|
except NameError:
|
|
|
from sets import Set as set
|
|
from sets import Set as set
|
|
|
|
|
|
|
|
-import hashlib
|
|
|
|
|
-import inspect
|
|
|
|
|
-import json
|
|
|
|
|
-import re
|
|
|
|
|
-import uuid
|
|
|
|
|
-
|
|
|
|
|
|
|
|
|
|
class GCEKeyPair(BaseKeyPair):
|
|
class GCEKeyPair(BaseKeyPair):
|
|
|
|
|
|
|
@@ -187,8 +196,11 @@ class GCERegion(BaseRegion):
|
|
|
"""
|
|
"""
|
|
|
Accesss information about placement zones within this region.
|
|
Accesss information about placement zones within this region.
|
|
|
"""
|
|
"""
|
|
|
- zones_response = self._provider.gce_compute.zones().list(
|
|
|
|
|
- project=self._provider.project_name).execute()
|
|
|
|
|
|
|
+ zones_response = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .zones()
|
|
|
|
|
+ .list(project=self._provider.project_name)
|
|
|
|
|
+ .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['name'], self.name)
|
|
return [GCEPlacementZone(self._provider, zone['name'], self.name)
|
|
@@ -285,11 +297,12 @@ class GCEFirewallsDelegate(object):
|
|
|
firewall['sourceTags'] = [source_tag]
|
|
firewall['sourceTags'] = [source_tag]
|
|
|
project_name = self._provider.project_name
|
|
project_name = self._provider.project_name
|
|
|
try:
|
|
try:
|
|
|
- response = (self._provider.gce_compute
|
|
|
|
|
- .firewalls()
|
|
|
|
|
- .insert(project=project_name,
|
|
|
|
|
- body=firewall)
|
|
|
|
|
- .execute())
|
|
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .firewalls()
|
|
|
|
|
+ .insert(project=project_name,
|
|
|
|
|
+ body=firewall)
|
|
|
|
|
+ .execute())
|
|
|
self._provider.wait_for_operation(response)
|
|
self._provider.wait_for_operation(response)
|
|
|
# TODO: process the response and handle errors.
|
|
# TODO: process the response and handle errors.
|
|
|
except:
|
|
except:
|
|
@@ -314,7 +327,8 @@ class GCEFirewallsDelegate(object):
|
|
|
if not self._check_list_in_dict(firewall, 'sourceRanges',
|
|
if not self._check_list_in_dict(firewall, 'sourceRanges',
|
|
|
source_range):
|
|
source_range):
|
|
|
continue
|
|
continue
|
|
|
- if not self._check_list_in_dict(firewall, 'sourceTags', source_tag):
|
|
|
|
|
|
|
+ if not self._check_list_in_dict(firewall, 'sourceTags',
|
|
|
|
|
+ source_tag):
|
|
|
continue
|
|
continue
|
|
|
return firewall['id']
|
|
return firewall['id']
|
|
|
return None
|
|
return None
|
|
@@ -328,7 +342,7 @@ class GCEFirewallsDelegate(object):
|
|
|
if firewall['id'] != firewall_id:
|
|
if firewall['id'] != firewall_id:
|
|
|
continue
|
|
continue
|
|
|
if ('sourceRanges' in firewall and
|
|
if ('sourceRanges' in firewall and
|
|
|
- len(firewall['sourceRanges']) == 1):
|
|
|
|
|
|
|
+ len(firewall['sourceRanges']) == 1):
|
|
|
info['source_range'] = firewall['sourceRanges'][0]
|
|
info['source_range'] = firewall['sourceRanges'][0]
|
|
|
if 'sourceTags' in firewall and len(firewall['sourceTags']) == 1:
|
|
if 'sourceTags' in firewall and len(firewall['sourceTags']) == 1:
|
|
|
info['source_tag'] = firewall['sourceTags'][0]
|
|
info['source_tag'] = firewall['sourceTags'][0]
|
|
@@ -337,7 +351,7 @@ class GCEFirewallsDelegate(object):
|
|
|
if 'IPProtocol' in firewall['allowed'][0]:
|
|
if 'IPProtocol' in firewall['allowed'][0]:
|
|
|
info['ip_protocol'] = firewall['allowed'][0]['IPProtocol']
|
|
info['ip_protocol'] = firewall['allowed'][0]['IPProtocol']
|
|
|
if ('ports' in firewall['allowed'][0] and
|
|
if ('ports' in firewall['allowed'][0] and
|
|
|
- len(firewall['allowed'][0]['ports']) == 1):
|
|
|
|
|
|
|
+ len(firewall['allowed'][0]['ports']) == 1):
|
|
|
info['port'] = firewall['allowed'][0]['ports'][0]
|
|
info['port'] = firewall['allowed'][0]['ports'][0]
|
|
|
info['network_name'] = self.network_name(firewall)
|
|
info['network_name'] = self.network_name(firewall)
|
|
|
return info
|
|
return info
|
|
@@ -362,7 +376,8 @@ class GCEFirewallsDelegate(object):
|
|
|
if 'items' not in self._list_response:
|
|
if 'items' not in self._list_response:
|
|
|
return
|
|
return
|
|
|
for firewall in self._list_response['items']:
|
|
for firewall in self._list_response['items']:
|
|
|
- if 'targetTags' not in firewall or len(firewall['targetTags']) != 1:
|
|
|
|
|
|
|
+ if ('targetTags' not in firewall or
|
|
|
|
|
+ len(firewall['targetTags']) != 1):
|
|
|
continue
|
|
continue
|
|
|
if 'allowed' not in firewall or len(firewall['allowed']) != 1:
|
|
if 'allowed' not in firewall or len(firewall['allowed']) != 1:
|
|
|
continue
|
|
continue
|
|
@@ -381,11 +396,12 @@ class GCEFirewallsDelegate(object):
|
|
|
"""
|
|
"""
|
|
|
project_name = self._provider.project_name
|
|
project_name = self._provider.project_name
|
|
|
try:
|
|
try:
|
|
|
- response = (self._provider.gce_compute
|
|
|
|
|
- .firewalls()
|
|
|
|
|
- .delete(project=project_name,
|
|
|
|
|
- firewall=firewall['name'])
|
|
|
|
|
- .execute())
|
|
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .firewalls()
|
|
|
|
|
+ .delete(project=project_name,
|
|
|
|
|
+ firewall=firewall['name'])
|
|
|
|
|
+ .execute())
|
|
|
self._provider.wait_for_operation(response)
|
|
self._provider.wait_for_operation(response)
|
|
|
except:
|
|
except:
|
|
|
return False
|
|
return False
|
|
@@ -396,11 +412,9 @@ class GCEFirewallsDelegate(object):
|
|
|
"""
|
|
"""
|
|
|
Sync the local cache of all firewalls with the server.
|
|
Sync the local cache of all firewalls with the server.
|
|
|
"""
|
|
"""
|
|
|
- self._list_response = (
|
|
|
|
|
- self._provider.gce_compute
|
|
|
|
|
- .firewalls()
|
|
|
|
|
- .list(project=self._provider.project_name)
|
|
|
|
|
- .execute())
|
|
|
|
|
|
|
+ self._list_response = list(
|
|
|
|
|
+ helpers.iter_all(self._provider.gce_compute.firewalls(),
|
|
|
|
|
+ project=self._provider.project_name))
|
|
|
|
|
|
|
|
def _check_list_in_dict(self, dictionary, field_name, value):
|
|
def _check_list_in_dict(self, dictionary, field_name, value):
|
|
|
"""
|
|
"""
|
|
@@ -408,9 +422,8 @@ class GCEFirewallsDelegate(object):
|
|
|
"""
|
|
"""
|
|
|
if field_name not in dictionary:
|
|
if field_name not in dictionary:
|
|
|
return value is None
|
|
return value is None
|
|
|
- if (value is None or
|
|
|
|
|
- len(dictionary[field_name]) != 1 or
|
|
|
|
|
- dictionary[field_name][0] != value):
|
|
|
|
|
|
|
+ if (value is None or len(dictionary[field_name]) != 1 or
|
|
|
|
|
+ dictionary[field_name][0] != value):
|
|
|
return False
|
|
return False
|
|
|
return True
|
|
return True
|
|
|
|
|
|
|
@@ -532,7 +545,7 @@ class GCESecurityGroupRule(BaseSecurityGroupRule):
|
|
|
return None
|
|
return None
|
|
|
if 'target_tag' not in info or info['network_name'] is None:
|
|
if 'target_tag' not in info or info['network_name'] is None:
|
|
|
return None
|
|
return None
|
|
|
- network = delegate.network.get_by_name(info['network_name'])
|
|
|
|
|
|
|
+ network = self._delegate.network.get_by_name(info['network_name'])
|
|
|
if network is None:
|
|
if network is None:
|
|
|
return None
|
|
return None
|
|
|
return GCESecurityGroup(self._delegate, info['target_tag'], network)
|
|
return GCESecurityGroup(self._delegate, info['target_tag'], network)
|
|
@@ -666,9 +679,12 @@ class GCEMachineImage(BaseMachineImage):
|
|
|
"""
|
|
"""
|
|
|
Delete this image
|
|
Delete this image
|
|
|
"""
|
|
"""
|
|
|
- request = self._provider.gce_compute.images().delete(
|
|
|
|
|
- project=self._provider.project_name, image=self.name)
|
|
|
|
|
- request.execute()
|
|
|
|
|
|
|
+ (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .images()
|
|
|
|
|
+ .delete(project=self._provider.project_name,
|
|
|
|
|
+ image=self.name)
|
|
|
|
|
+ .execute())
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def state(self):
|
|
def state(self):
|
|
@@ -689,11 +705,11 @@ class GCEMachineImage(BaseMachineImage):
|
|
|
cb.log.warning("Project name is not found.")
|
|
cb.log.warning("Project name is not found.")
|
|
|
return
|
|
return
|
|
|
try:
|
|
try:
|
|
|
- response = self._provider.gce_compute \
|
|
|
|
|
- .images() \
|
|
|
|
|
- .get(project=project,
|
|
|
|
|
- image=self.name) \
|
|
|
|
|
- .execute()
|
|
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .images()
|
|
|
|
|
+ .get(project=project, image=self.name)
|
|
|
|
|
+ .execute())
|
|
|
if response:
|
|
if response:
|
|
|
# pylint:disable=protected-access
|
|
# pylint:disable=protected-access
|
|
|
self._gce_image = response
|
|
self._gce_image = response
|
|
@@ -767,10 +783,10 @@ class GCEInstance(BaseInstance):
|
|
|
access_configs = network_interfaces[0].get('accessConfigs')
|
|
access_configs = network_interfaces[0].get('accessConfigs')
|
|
|
if access_configs is not None and len(access_configs) > 0:
|
|
if access_configs is not None and len(access_configs) > 0:
|
|
|
# https://cloud.google.com/compute/docs/reference/beta/instances
|
|
# https://cloud.google.com/compute/docs/reference/beta/instances
|
|
|
- # An array of configurations for this interface. Currently, only
|
|
|
|
|
- # one access config, ONE_TO_ONE_NAT, is supported. If there are
|
|
|
|
|
- # no accessConfigs specified, then this instance will have no
|
|
|
|
|
- # external internet access.
|
|
|
|
|
|
|
+ # An array of configurations for this interface. Currently,
|
|
|
|
|
+ # only one access config, ONE_TO_ONE_NAT, is supported. If
|
|
|
|
|
+ # there are no accessConfigs specified, then this instance will
|
|
|
|
|
+ # have no external internet access.
|
|
|
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'])
|
|
@@ -820,41 +836,45 @@ class GCEInstance(BaseInstance):
|
|
|
Reboot this instance.
|
|
Reboot this instance.
|
|
|
"""
|
|
"""
|
|
|
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()
|
|
|
|
|
|
|
+ (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .instances()
|
|
|
|
|
+ .start(project=self._provider.project_name,
|
|
|
|
|
+ zone=self._provider.default_zone,
|
|
|
|
|
+ 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()
|
|
|
|
|
|
|
+ (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .instances()
|
|
|
|
|
+ .reset(project=self._provider.project_name,
|
|
|
|
|
+ zone=self._provider.default_zone,
|
|
|
|
|
+ instance=self.name)
|
|
|
|
|
+ .execute())
|
|
|
|
|
|
|
|
def terminate(self):
|
|
def terminate(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()
|
|
|
|
|
|
|
+ (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .instances()
|
|
|
|
|
+ .delete(project=self._provider.project_name,
|
|
|
|
|
+ zone=self._provider.default_zone,
|
|
|
|
|
+ instance=self.name)
|
|
|
|
|
+ .execute())
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
+ (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .instances()
|
|
|
|
|
+ .stop(project=self._provider.project_name,
|
|
|
|
|
+ zone=self._provider.default_zone,
|
|
|
|
|
+ instance=self.name)
|
|
|
|
|
+ .execute())
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def image_id(self):
|
|
def image_id(self):
|
|
@@ -927,15 +947,10 @@ class GCEInstance(BaseInstance):
|
|
|
"""
|
|
"""
|
|
|
self_url = self._provider.parse_url(self._gce_instance['selfLink'])
|
|
self_url = self._provider.parse_url(self._gce_instance['selfLink'])
|
|
|
try:
|
|
try:
|
|
|
- response = (self._provider
|
|
|
|
|
- .gce_compute
|
|
|
|
|
- .targetInstances()
|
|
|
|
|
- .list(project=self_url.parameters['project'],
|
|
|
|
|
- zone=self_url.parameters['zone'])
|
|
|
|
|
- .execute())
|
|
|
|
|
- if 'items' not in response:
|
|
|
|
|
- return None
|
|
|
|
|
- for target_instance in response['items']:
|
|
|
|
|
|
|
+ for target_instance in helpers.iter_all(
|
|
|
|
|
+ self._provider.gce_compute.targetInstances(),
|
|
|
|
|
+ project=self_url.parameters['project'],
|
|
|
|
|
+ zone=self_url.parameters['zone']):
|
|
|
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
|
|
@@ -959,16 +974,17 @@ class GCEInstance(BaseInstance):
|
|
|
'instance': self._gce_instance['selfLink']}
|
|
'instance': self._gce_instance['selfLink']}
|
|
|
try:
|
|
try:
|
|
|
response = (self._provider
|
|
response = (self._provider
|
|
|
- .gce_compute
|
|
|
|
|
- .targetInstances()
|
|
|
|
|
- .insert(project=self_url.parameters['project'],
|
|
|
|
|
- zone=self_url.parameters['zone'],
|
|
|
|
|
- body=body)
|
|
|
|
|
- .execute())
|
|
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .targetInstances()
|
|
|
|
|
+ .insert(project=self_url.parameters['project'],
|
|
|
|
|
+ zone=self_url.parameters['zone'],
|
|
|
|
|
+ body=body)
|
|
|
|
|
+ .execute())
|
|
|
self._provider.wait_for_operation(
|
|
self._provider.wait_for_operation(
|
|
|
response, zone=self_url.parameters['zone'])
|
|
response, zone=self_url.parameters['zone'])
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
- cb.log.warning('Exception while inserting a target instance: %s', e)
|
|
|
|
|
|
|
+ cb.log.warning('Exception while inserting a target instance: %s',
|
|
|
|
|
+ e)
|
|
|
return None
|
|
return None
|
|
|
|
|
|
|
|
# The following method should find the target instance that we
|
|
# The following method should find the target instance that we
|
|
@@ -984,32 +1000,28 @@ class GCEInstance(BaseInstance):
|
|
|
new_name = target_instance['name']
|
|
new_name = target_instance['name']
|
|
|
new_url = target_instance['selfLink']
|
|
new_url = target_instance['selfLink']
|
|
|
try:
|
|
try:
|
|
|
- response = (self._provider.gce_compute
|
|
|
|
|
- .forwardingRules()
|
|
|
|
|
- .list(project=self._provider.project_name,
|
|
|
|
|
- region=ip.region)
|
|
|
|
|
- .execute())
|
|
|
|
|
- if 'items' not in response:
|
|
|
|
|
- return False
|
|
|
|
|
- for rule in response['items']:
|
|
|
|
|
- if rule['IPAddress'] == ip.public_ip:
|
|
|
|
|
- parsed_target_url = self._provider.parse_url(rule['target'])
|
|
|
|
|
- old_zone = parsed_target_url.parameters['zone']
|
|
|
|
|
- old_name = parsed_target_url.parameters['targetInstance']
|
|
|
|
|
- if old_zone == new_zone and old_name == new_name:
|
|
|
|
|
- return True
|
|
|
|
|
- response = (self._provider
|
|
|
|
|
- .gce_compute
|
|
|
|
|
- .forwardingRules()
|
|
|
|
|
- .setTarget(
|
|
|
|
|
- project=self._provider.project_name,
|
|
|
|
|
- region=ip.region,
|
|
|
|
|
- forwardingRule=rule['name'],
|
|
|
|
|
- body={'target': new_url})
|
|
|
|
|
- .execute())
|
|
|
|
|
- self._provider.wait_for_operation(response,
|
|
|
|
|
- region=ip.region)
|
|
|
|
|
|
|
+ for rule in helpers.iter_all(
|
|
|
|
|
+ self._provider.gce_compute.forwardingRules(),
|
|
|
|
|
+ project=self._provider.project_name,
|
|
|
|
|
+ region=ip.region):
|
|
|
|
|
+ if rule['IPAddress'] != ip.public_ip:
|
|
|
|
|
+ continue
|
|
|
|
|
+ parsed_target_url = self._provider.parse_url(rule['target'])
|
|
|
|
|
+ old_zone = parsed_target_url.parameters['zone']
|
|
|
|
|
+ old_name = parsed_target_url.parameters['targetInstance']
|
|
|
|
|
+ if old_zone == new_zone and old_name == new_name:
|
|
|
return True
|
|
return True
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .forwardingRules()
|
|
|
|
|
+ .setTarget(
|
|
|
|
|
+ project=self._provider.project_name,
|
|
|
|
|
+ region=ip.region,
|
|
|
|
|
+ forwardingRule=rule['name'],
|
|
|
|
|
+ body={'target': new_url})
|
|
|
|
|
+ .execute())
|
|
|
|
|
+ self._provider.wait_for_operation(response, region=ip.region)
|
|
|
|
|
+ return True
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
cb.log.warning(
|
|
cb.log.warning(
|
|
|
'Exception while listing/changing forwarding rules: %s', e)
|
|
'Exception while listing/changing forwarding rules: %s', e)
|
|
@@ -1028,16 +1040,17 @@ class GCEInstance(BaseInstance):
|
|
|
'IPAddress': ip.public_ip,
|
|
'IPAddress': ip.public_ip,
|
|
|
'target': target_instance['selfLink']}
|
|
'target': target_instance['selfLink']}
|
|
|
try:
|
|
try:
|
|
|
- response = (self._provider.gce_compute
|
|
|
|
|
- .forwardingRules()
|
|
|
|
|
- .insert(
|
|
|
|
|
- project=self._provider.project_name,
|
|
|
|
|
- region=ip.region,
|
|
|
|
|
- body=body)
|
|
|
|
|
- .execute())
|
|
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .forwardingRules()
|
|
|
|
|
+ .insert(project=self._provider.project_name,
|
|
|
|
|
+ region=ip.region,
|
|
|
|
|
+ body=body)
|
|
|
|
|
+ .execute())
|
|
|
self._provider.wait_for_operation(response, region=ip.region)
|
|
self._provider.wait_for_operation(response, region=ip.region)
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
- cb.log.warning('Exception while inserting a forwarding rule: %s', e)
|
|
|
|
|
|
|
+ cb.log.warning('Exception while inserting a forwarding rule: %s',
|
|
|
|
|
+ e)
|
|
|
return False
|
|
return False
|
|
|
return True
|
|
return True
|
|
|
|
|
|
|
@@ -1049,38 +1062,36 @@ class GCEInstance(BaseInstance):
|
|
|
.parameters['zone'])
|
|
.parameters['zone'])
|
|
|
name = target_instance['name']
|
|
name = target_instance['name']
|
|
|
try:
|
|
try:
|
|
|
- response = (self._provider.gce_compute
|
|
|
|
|
- .forwardingRules()
|
|
|
|
|
- .list(project=self._provider.project_name,
|
|
|
|
|
- region=ip.region)
|
|
|
|
|
- .execute())
|
|
|
|
|
- if 'items' not in response:
|
|
|
|
|
- return False
|
|
|
|
|
- for rule in response['items']:
|
|
|
|
|
- if rule['IPAddress'] == ip.public_ip:
|
|
|
|
|
- parsed_target_url = self._provider.parse_url(rule['target'])
|
|
|
|
|
- temp_zone = parsed_target_url.parameters['zone']
|
|
|
|
|
- temp_name = parsed_target_url.parameters['targetInstance']
|
|
|
|
|
- if temp_zone != zone or temp_name != name:
|
|
|
|
|
- cb.log.warning('"%s" is forwarded to "%s" in zone "%s"',
|
|
|
|
|
- ip.public_ip, temp_name, temp_zone)
|
|
|
|
|
- return False
|
|
|
|
|
- response = (self._provider
|
|
|
|
|
- .gce_compute
|
|
|
|
|
- .forwardingRules()
|
|
|
|
|
- .delete(
|
|
|
|
|
- project=self._provider.project_name,
|
|
|
|
|
- region=ip.region,
|
|
|
|
|
- forwardingRule=rule['name'])
|
|
|
|
|
- .execute())
|
|
|
|
|
- self._provider.wait_for_operation(response,
|
|
|
|
|
- region=ip.region)
|
|
|
|
|
|
|
+ for rule in helpers.iter_all(
|
|
|
|
|
+ self._provider.gce_compute.forwardingRules(),
|
|
|
|
|
+ project=self._provider.project_name,
|
|
|
|
|
+ region=ip.region):
|
|
|
|
|
+ if rule['IPAddress'] != ip.public_ip:
|
|
|
|
|
+ continue
|
|
|
|
|
+ parsed_target_url = self._provider.parse_url(rule['target'])
|
|
|
|
|
+ temp_zone = parsed_target_url.parameters['zone']
|
|
|
|
|
+ temp_name = parsed_target_url.parameters['targetInstance']
|
|
|
|
|
+ if temp_zone != zone or temp_name != name:
|
|
|
|
|
+ cb.log.warning(
|
|
|
|
|
+ '"%s" is forwarded to "%s" in zone "%s"',
|
|
|
|
|
+ ip.public_ip, temp_name, temp_zone)
|
|
|
|
|
+ return False
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .forwardingRules()
|
|
|
|
|
+ .delete(
|
|
|
|
|
+ project=self._provider.project_name,
|
|
|
|
|
+ region=ip.region,
|
|
|
|
|
+ forwardingRule=rule['name'])
|
|
|
|
|
+ .execute())
|
|
|
|
|
+ self._provider.wait_for_operation(response, region=ip.region)
|
|
|
|
|
+ return True
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
cb.log.warning(
|
|
cb.log.warning(
|
|
|
'Exception while listing/deleting forwarding rules: %s', e)
|
|
'Exception while listing/deleting forwarding rules: %s', e)
|
|
|
return False
|
|
return False
|
|
|
return True
|
|
return True
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
def add_floating_ip(self, ip_address):
|
|
def add_floating_ip(self, ip_address):
|
|
|
"""
|
|
"""
|
|
|
Add an elastic IP address to this instance.
|
|
Add an elastic IP address to this instance.
|
|
@@ -1095,8 +1106,9 @@ class GCEInstance(BaseInstance):
|
|
|
return
|
|
return
|
|
|
target_instance = self._get_target_instance()
|
|
target_instance = self._get_target_instance()
|
|
|
if not target_instance:
|
|
if not target_instance:
|
|
|
- cb.log.warning('Could not create a targetInstance for "%s"',
|
|
|
|
|
- self.name)
|
|
|
|
|
|
|
+ cb.log.warning(
|
|
|
|
|
+ 'Could not create a targetInstance for "%s"',
|
|
|
|
|
+ self.name)
|
|
|
return
|
|
return
|
|
|
if not self._forward(ip, target_instance):
|
|
if not self._forward(ip, target_instance):
|
|
|
cb.log.warning('Could not forward "%s" to "%s"',
|
|
cb.log.warning('Could not forward "%s" to "%s"',
|
|
@@ -1113,7 +1125,7 @@ class GCEInstance(BaseInstance):
|
|
|
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(
|
|
|
'Floating IP "%s" is not associated to "%s".',
|
|
'Floating IP "%s" is not associated to "%s".',
|
|
|
- ip_address, self.name)
|
|
|
|
|
|
|
+ ip_address, self.name)
|
|
|
return
|
|
return
|
|
|
target_instance = self._get_target_instance()
|
|
target_instance = self._get_target_instance()
|
|
|
if not target_instance:
|
|
if not target_instance:
|
|
@@ -1142,6 +1154,7 @@ class GCEInstance(BaseInstance):
|
|
|
self._gce_instance = self._provider.get_gce_resource_data(
|
|
self._gce_instance = self._provider.get_gce_resource_data(
|
|
|
self._gce_instance.get('selfLink'))
|
|
self._gce_instance.get('selfLink'))
|
|
|
|
|
|
|
|
|
|
+
|
|
|
class GCENetwork(BaseNetwork):
|
|
class GCENetwork(BaseNetwork):
|
|
|
|
|
|
|
|
def __init__(self, provider, network):
|
|
def __init__(self, provider, network):
|
|
@@ -1175,11 +1188,11 @@ class GCENetwork(BaseNetwork):
|
|
|
def delete(self):
|
|
def delete(self):
|
|
|
try:
|
|
try:
|
|
|
response = (self._provider
|
|
response = (self._provider
|
|
|
- .gce_compute
|
|
|
|
|
- .networks()
|
|
|
|
|
- .delete(project=self._provider.project_name,
|
|
|
|
|
- network=self.name)
|
|
|
|
|
- .execute())
|
|
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .networks()
|
|
|
|
|
+ .delete(project=self._provider.project_name,
|
|
|
|
|
+ network=self.name)
|
|
|
|
|
+ .execute())
|
|
|
if 'error' in response:
|
|
if 'error' in response:
|
|
|
return False
|
|
return False
|
|
|
self._provider.wait_for_operation(response)
|
|
self._provider.wait_for_operation(response)
|
|
@@ -1188,14 +1201,15 @@ class GCENetwork(BaseNetwork):
|
|
|
return True
|
|
return True
|
|
|
|
|
|
|
|
def subnets(self):
|
|
def subnets(self):
|
|
|
- raise NotImplementedError("To be implemented")
|
|
|
|
|
|
|
+ return self._provider.network.subnets.list()
|
|
|
|
|
|
|
|
def create_subnet(self, cidr_block, name=None):
|
|
def create_subnet(self, cidr_block, name=None):
|
|
|
- raise NotImplementedError("To be implemented")
|
|
|
|
|
|
|
+ return self._provider.network.subnets.create(self, cidr_block, name)
|
|
|
|
|
|
|
|
def refresh(self):
|
|
def refresh(self):
|
|
|
return self.state
|
|
return self.state
|
|
|
|
|
|
|
|
|
|
+
|
|
|
class GCEFloatingIP(BaseFloatingIP):
|
|
class GCEFloatingIP(BaseFloatingIP):
|
|
|
_DEAD_INSTANCE = 'dead instance'
|
|
_DEAD_INSTANCE = 'dead instance'
|
|
|
|
|
|
|
@@ -1223,9 +1237,9 @@ class GCEFloatingIP(BaseFloatingIP):
|
|
|
if target['kind'] == 'compute#targetInstance':
|
|
if target['kind'] == 'compute#targetInstance':
|
|
|
url = provider.parse_url(target['instance'])
|
|
url = provider.parse_url(target['instance'])
|
|
|
try:
|
|
try:
|
|
|
- self._target_instance = url.get()
|
|
|
|
|
|
|
+ self._target_instance = url.get()
|
|
|
except:
|
|
except:
|
|
|
- self._target_instance = GCEFloatingIP._DEAD_INSTANCE
|
|
|
|
|
|
|
+ self._target_instance = GCEFloatingIP._DEAD_INSTANCE
|
|
|
else:
|
|
else:
|
|
|
cb.log.warning('Address "%s" is forwarded to a %s',
|
|
cb.log.warning('Address "%s" is forwarded to a %s',
|
|
|
floating_ip['address'], target['kind'])
|
|
floating_ip['address'], target['kind'])
|
|
@@ -1248,7 +1262,7 @@ class GCEFloatingIP(BaseFloatingIP):
|
|
|
@property
|
|
@property
|
|
|
def private_ip(self):
|
|
def private_ip(self):
|
|
|
if (not self._target_instance or
|
|
if (not self._target_instance or
|
|
|
- self._target_instance == GCEFloatingIP._DEAD_INSTANCE):
|
|
|
|
|
|
|
+ self._target_instance == GCEFloatingIP._DEAD_INSTANCE):
|
|
|
return None
|
|
return None
|
|
|
return self._target_instance['networkInterfaces'][0]['networkIP']
|
|
return self._target_instance['networkInterfaces'][0]['networkIP']
|
|
|
|
|
|
|
@@ -1256,25 +1270,125 @@ class GCEFloatingIP(BaseFloatingIP):
|
|
|
return True if self._target_instance else False
|
|
return True if self._target_instance else False
|
|
|
|
|
|
|
|
def delete(self):
|
|
def delete(self):
|
|
|
- project_name = self._provider.project_name
|
|
|
|
|
- # First, delete the forwarding rule, if there is any.
|
|
|
|
|
- if self._rule:
|
|
|
|
|
- response = (self._provider.gce_compute
|
|
|
|
|
- .forwardingRules()
|
|
|
|
|
- .delete(project=project_name,
|
|
|
|
|
- region=self._region,
|
|
|
|
|
- forwardingRule=self._rule['name'])
|
|
|
|
|
- .execute())
|
|
|
|
|
- self._provider.wait_for_operation(response, region=self._region)
|
|
|
|
|
-
|
|
|
|
|
- # Release the address.
|
|
|
|
|
- response = (self._provider.gce_compute
|
|
|
|
|
- .addresses()
|
|
|
|
|
- .delete(project=project_name,
|
|
|
|
|
- region=self._region,
|
|
|
|
|
- address=self._ip['name'])
|
|
|
|
|
- .execute())
|
|
|
|
|
- self._provider.wait_for_operation(response, region=self._region)
|
|
|
|
|
|
|
+ project_name = self._provider.project_name
|
|
|
|
|
+ # First, delete the forwarding rule, if there is any.
|
|
|
|
|
+ if self._rule:
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .forwardingRules()
|
|
|
|
|
+ .delete(project=project_name,
|
|
|
|
|
+ region=self._region,
|
|
|
|
|
+ forwardingRule=self._rule['name'])
|
|
|
|
|
+ .execute())
|
|
|
|
|
+ self._provider.wait_for_operation(response, region=self._region)
|
|
|
|
|
+
|
|
|
|
|
+ # Release the address.
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .addresses()
|
|
|
|
|
+ .delete(project=project_name,
|
|
|
|
|
+ region=self._region,
|
|
|
|
|
+ address=self._ip['name'])
|
|
|
|
|
+ .execute())
|
|
|
|
|
+ self._provider.wait_for_operation(response, region=self._region)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class GCERouter(BaseRouter):
|
|
|
|
|
+
|
|
|
|
|
+ def __init__(self, provider, router):
|
|
|
|
|
+ super(GCERouter, self).__init__(provider)
|
|
|
|
|
+ self._router = router
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def id(self):
|
|
|
|
|
+ return self._router['id']
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def name(self):
|
|
|
|
|
+ return self._router['name']
|
|
|
|
|
+
|
|
|
|
|
+ def refresh(self):
|
|
|
|
|
+ self._router = self._provider.parse_url(self._router['selfLink']).get()
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def state(self):
|
|
|
|
|
+ # GCE routers are always attached to a network.
|
|
|
|
|
+ return RouterState.ATTACHED
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def network_id(self):
|
|
|
|
|
+ network = self._provider.parse_url(self._router['network']).get()
|
|
|
|
|
+ return network['id']
|
|
|
|
|
+
|
|
|
|
|
+ def delete(self):
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .routers()
|
|
|
|
|
+ .delete(project=self._provider.project_name,
|
|
|
|
|
+ region=self._router['region'],
|
|
|
|
|
+ router=self._router['name'])
|
|
|
|
|
+ .execute())
|
|
|
|
|
+ self._provider.wait_for_operation(response,
|
|
|
|
|
+ region=self._router['region'])
|
|
|
|
|
+
|
|
|
|
|
+ def attach_network(self, network_id):
|
|
|
|
|
+ if network_id == self.network_id:
|
|
|
|
|
+ return
|
|
|
|
|
+ cb.log.warning('GCE routers should be attached at creation time')
|
|
|
|
|
+
|
|
|
|
|
+ def detach_network(self, network_id):
|
|
|
|
|
+ cb.log.warning('GCE routers are always attached')
|
|
|
|
|
+
|
|
|
|
|
+ def add_route(self, subnet_id):
|
|
|
|
|
+ cb.log.warning('Not implemented')
|
|
|
|
|
+
|
|
|
|
|
+ def remove_route(self, subnet_id):
|
|
|
|
|
+ cb.log.warning('Not implemented')
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class GCESubnet(BaseSubnet):
|
|
|
|
|
+
|
|
|
|
|
+ def __init__(self, provider, subnet):
|
|
|
|
|
+ super(GCESubnet, self).__init__(provider)
|
|
|
|
|
+ self._subnet = subnet
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def id(self):
|
|
|
|
|
+ return self._subnet['id']
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def name(self):
|
|
|
|
|
+ return self._subnet['name']
|
|
|
|
|
+
|
|
|
|
|
+ @name.setter
|
|
|
|
|
+ def name(self, value):
|
|
|
|
|
+ if value == self.name:
|
|
|
|
|
+ return
|
|
|
|
|
+ cb.log.warning('Cannot change the name of a GCE subnetwork')
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def cidr_block(self):
|
|
|
|
|
+ return self._subnet['ipCidrRange']
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def network_url(self):
|
|
|
|
|
+ return self._subnet['network']
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def network_id(self):
|
|
|
|
|
+ return self._provider.parse_url(self.network_url).get()['id']
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def region(self):
|
|
|
|
|
+ return self._subnet['region']
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def zone(self):
|
|
|
|
|
+ raise NotImplementedError('To be implemented')
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def delete(self):
|
|
|
|
|
+ return self._provider.network.subnets.delete(self)
|
|
|
|
|
|
|
|
|
|
|
|
|
class GCEVolume(BaseVolume):
|
|
class GCEVolume(BaseVolume):
|
|
@@ -1319,21 +1433,22 @@ class GCEVolume(BaseVolume):
|
|
|
@description.setter
|
|
@description.setter
|
|
|
def description(self, value):
|
|
def description(self, value):
|
|
|
request_body = {
|
|
request_body = {
|
|
|
- 'labels': {'description': value.replace(' ', '_').lower(),},
|
|
|
|
|
|
|
+ 'labels': {'description': value.replace(' ', '_').lower()},
|
|
|
'labelFingerprint': self._volume.get('labelFingerprint'),
|
|
'labelFingerprint': self._volume.get('labelFingerprint'),
|
|
|
}
|
|
}
|
|
|
try:
|
|
try:
|
|
|
- response = (self._provider.gce_compute
|
|
|
|
|
- .disks()
|
|
|
|
|
- .setLabels(
|
|
|
|
|
- project=self._provider.project_name,
|
|
|
|
|
|
|
+ (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .disks()
|
|
|
|
|
+ .setLabels(project=self._provider.project_name,
|
|
|
zone=self._provider.default_zone,
|
|
zone=self._provider.default_zone,
|
|
|
resource=self.name,
|
|
resource=self.name,
|
|
|
- body=request_body).execute())
|
|
|
|
|
|
|
+ body=request_body)
|
|
|
|
|
+ .execute())
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
- cb.log.warning('Exception while setting volume description: %s.'
|
|
|
|
|
- 'Check for invalid characters in description. Should'
|
|
|
|
|
- 'confirm to RFC1035.', e)
|
|
|
|
|
|
|
+ cb.log.warning('Exception while setting volume description: %s. '
|
|
|
|
|
+ 'Check for invalid characters in description. '
|
|
|
|
|
+ 'Should confirm to RFC1035.', e)
|
|
|
raise e
|
|
raise e
|
|
|
self.refresh()
|
|
self.refresh()
|
|
|
|
|
|
|
@@ -1361,7 +1476,7 @@ class GCEVolume(BaseVolume):
|
|
|
# the first user of a disk.
|
|
# the first user of a disk.
|
|
|
if 'users' in self._volume and len(self._volume) > 0:
|
|
if 'users' in self._volume and len(self._volume) > 0:
|
|
|
if len(self._volume) > 1:
|
|
if len(self._volume) > 1:
|
|
|
- cb.log.warning("This volume is attached to multiple instances.")
|
|
|
|
|
|
|
+ cb.log.warning("This volume is attached to multiple instances")
|
|
|
return BaseAttachmentInfo(self,
|
|
return BaseAttachmentInfo(self,
|
|
|
self._volume.get('users')[0],
|
|
self._volume.get('users')[0],
|
|
|
None)
|
|
None)
|
|
@@ -1386,13 +1501,14 @@ class GCEVolume(BaseVolume):
|
|
|
instance_name = instance.name if isinstance(
|
|
instance_name = instance.name if isinstance(
|
|
|
instance,
|
|
instance,
|
|
|
GCEInstance) else instance
|
|
GCEInstance) else instance
|
|
|
- response = (self._provider.gce_compute
|
|
|
|
|
- .instances()
|
|
|
|
|
- .attachDisk(
|
|
|
|
|
- project=self._provider.project_name,
|
|
|
|
|
- zone=self._provider.default_zone,
|
|
|
|
|
- instance=instance_name,
|
|
|
|
|
- body=attach_disk_body).execute())
|
|
|
|
|
|
|
+ (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .instances()
|
|
|
|
|
+ .attachDisk(project=self._provider.project_name,
|
|
|
|
|
+ zone=self._provider.default_zone,
|
|
|
|
|
+ instance=instance_name,
|
|
|
|
|
+ body=attach_disk_body)
|
|
|
|
|
+ .execute())
|
|
|
|
|
|
|
|
def detach(self, force=False):
|
|
def detach(self, force=False):
|
|
|
"""
|
|
"""
|
|
@@ -1409,17 +1525,18 @@ class GCEVolume(BaseVolume):
|
|
|
device_name = None
|
|
device_name = None
|
|
|
for disk in instance_data['disks']:
|
|
for disk in instance_data['disks']:
|
|
|
if ('source' in disk and 'deviceName' in disk and
|
|
if ('source' in disk and 'deviceName' in disk and
|
|
|
- disk['source'] == self.id):
|
|
|
|
|
|
|
+ disk['source'] == self.id):
|
|
|
device_name = disk['deviceName']
|
|
device_name = disk['deviceName']
|
|
|
if not device_name:
|
|
if not device_name:
|
|
|
return
|
|
return
|
|
|
- response = (self._provider.gce_compute
|
|
|
|
|
- .instances()
|
|
|
|
|
- .detachDisk(
|
|
|
|
|
- project=self._provider.project_name,
|
|
|
|
|
- zone=self._provider.default_zone,
|
|
|
|
|
- instance=instance_data.get('name'),
|
|
|
|
|
- deviceName=device_name).execute())
|
|
|
|
|
|
|
+ (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .instances()
|
|
|
|
|
+ .detachDisk(project=self._provider.project_name,
|
|
|
|
|
+ zone=self._provider.default_zone,
|
|
|
|
|
+ instance=instance_data.get('name'),
|
|
|
|
|
+ deviceName=device_name)
|
|
|
|
|
+ .execute())
|
|
|
|
|
|
|
|
def create_snapshot(self, name, description=None):
|
|
def create_snapshot(self, name, description=None):
|
|
|
"""
|
|
"""
|
|
@@ -1432,12 +1549,13 @@ class GCEVolume(BaseVolume):
|
|
|
"""
|
|
"""
|
|
|
Delete this volume.
|
|
Delete this volume.
|
|
|
"""
|
|
"""
|
|
|
- response = (self._provider.gce_compute
|
|
|
|
|
- .disks()
|
|
|
|
|
- .delete(
|
|
|
|
|
- project=self._provider.project_name,
|
|
|
|
|
- zone=self._provider.default_zone,
|
|
|
|
|
- disk=self.name).execute())
|
|
|
|
|
|
|
+ (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .disks()
|
|
|
|
|
+ .delete(project=self._provider.project_name,
|
|
|
|
|
+ zone=self._provider.default_zone,
|
|
|
|
|
+ disk=self.name)
|
|
|
|
|
+ .execute())
|
|
|
|
|
|
|
|
@property
|
|
@property
|
|
|
def state(self):
|
|
def state(self):
|
|
@@ -1520,11 +1638,12 @@ class GCESnapshot(BaseSnapshot):
|
|
|
"""
|
|
"""
|
|
|
Delete this snapshot.
|
|
Delete this snapshot.
|
|
|
"""
|
|
"""
|
|
|
- response = (self._provider.gce_compute
|
|
|
|
|
- .snapshots()
|
|
|
|
|
- .delete(
|
|
|
|
|
- project=self._provider.project_name,
|
|
|
|
|
- snapshot=self.name).execute())
|
|
|
|
|
|
|
+ (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
|
|
+ .snapshots()
|
|
|
|
|
+ .delete(project=self._provider.project_name,
|
|
|
|
|
+ snapshot=self.name)
|
|
|
|
|
+ .execute())
|
|
|
|
|
|
|
|
def create_volume(self, placement, size=None, volume_type=None, iops=None):
|
|
def create_volume(self, placement, size=None, volume_type=None, iops=None):
|
|
|
"""
|
|
"""
|
|
@@ -1548,11 +1667,174 @@ class GCESnapshot(BaseSnapshot):
|
|
|
'type': vol_type,
|
|
'type': vol_type,
|
|
|
'sourceSnapshot': self.id
|
|
'sourceSnapshot': self.id
|
|
|
}
|
|
}
|
|
|
- operation = (self._provider.gce_compute
|
|
|
|
|
|
|
+ operation = (self._provider
|
|
|
|
|
+ .gce_compute
|
|
|
.disks()
|
|
.disks()
|
|
|
- .insert(
|
|
|
|
|
- project=self._provider.project_name,
|
|
|
|
|
- zone=placement,
|
|
|
|
|
- body=disk_body).execute())
|
|
|
|
|
|
|
+ .insert(project=self._provider.project_name,
|
|
|
|
|
+ zone=placement,
|
|
|
|
|
+ body=disk_body)
|
|
|
|
|
+ .execute())
|
|
|
return self._provider.block_store.volumes.get(
|
|
return self._provider.block_store.volumes.get(
|
|
|
operation.get('targetLink'))
|
|
operation.get('targetLink'))
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class GCSObject(BaseBucketObject):
|
|
|
|
|
+
|
|
|
|
|
+ def __init__(self, provider, bucket, obj):
|
|
|
|
|
+ super(GCSObject, self).__init__(provider)
|
|
|
|
|
+ self._bucket = bucket
|
|
|
|
|
+ self._obj = obj
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def id(self):
|
|
|
|
|
+ return self._obj['id']
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def name(self):
|
|
|
|
|
+ return self._obj['name']
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def size(self):
|
|
|
|
|
+ return self._obj['size']
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def last_modified(self):
|
|
|
|
|
+ return self._obj['updated']
|
|
|
|
|
+
|
|
|
|
|
+ def iter_content(self):
|
|
|
|
|
+ return io.BytesIO(self._provider
|
|
|
|
|
+ .gcp_storage
|
|
|
|
|
+ .objects()
|
|
|
|
|
+ .get_media(bucket=self._obj['bucket'],
|
|
|
|
|
+ object=self.name)
|
|
|
|
|
+ .execute())
|
|
|
|
|
+
|
|
|
|
|
+ def upload(self, data):
|
|
|
|
|
+ """
|
|
|
|
|
+ Set the contents of this object to the given text.
|
|
|
|
|
+ """
|
|
|
|
|
+ media_body = googleapiclient.http.MediaIoBaseUpload(
|
|
|
|
|
+ io.BytesIO(data), mimetype='plain/text')
|
|
|
|
|
+ response = self._bucket.create_object_with_media_body(self.name,
|
|
|
|
|
+ media_body)
|
|
|
|
|
+ if response:
|
|
|
|
|
+ self._obj = response
|
|
|
|
|
+
|
|
|
|
|
+ def upload_from_file(self, path):
|
|
|
|
|
+ """
|
|
|
|
|
+ Upload a binary file.
|
|
|
|
|
+ """
|
|
|
|
|
+ with open(path, 'rb') as f:
|
|
|
|
|
+ media_body = googleapiclient.http.MediaIoBaseUpload(
|
|
|
|
|
+ f, 'application/octet-stream')
|
|
|
|
|
+ response = self._bucket.create_object_with_media_body(self.name,
|
|
|
|
|
+ media_body)
|
|
|
|
|
+ if response:
|
|
|
|
|
+ self._obj = response
|
|
|
|
|
+
|
|
|
|
|
+ def delete(self):
|
|
|
|
|
+ (self._provider
|
|
|
|
|
+ .gcp_storage
|
|
|
|
|
+ .objects()
|
|
|
|
|
+ .delete(bucket=self._obj['bucket'], object=self.name)
|
|
|
|
|
+ .execute())
|
|
|
|
|
+
|
|
|
|
|
+ def generate_url(self, expires_in=0):
|
|
|
|
|
+ return self._obj['mediaLink']
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class GCSBucket(BaseBucket):
|
|
|
|
|
+
|
|
|
|
|
+ def __init__(self, provider, bucket):
|
|
|
|
|
+ super(GCSBucket, self).__init__(provider)
|
|
|
|
|
+ self._bucket = bucket
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def id(self):
|
|
|
|
|
+ return self._bucket['id']
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def name(self):
|
|
|
|
|
+ """
|
|
|
|
|
+ Get this bucket's name.
|
|
|
|
|
+ """
|
|
|
|
|
+ return self._bucket['name']
|
|
|
|
|
+
|
|
|
|
|
+ def get(self, name):
|
|
|
|
|
+ """
|
|
|
|
|
+ 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:
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+ def list(self, limit=None, marker=None, prefix=None):
|
|
|
|
|
+ """
|
|
|
|
|
+ List all objects within this bucket.
|
|
|
|
|
+ """
|
|
|
|
|
+ max_result = limit if limit is not None and limit < 500 else 500
|
|
|
|
|
+ try:
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gcp_storage
|
|
|
|
|
+ .objects()
|
|
|
|
|
+ .list(bucket=self.name,
|
|
|
|
|
+ prefix=prefix if prefix else '',
|
|
|
|
|
+ maxResults=max_result,
|
|
|
|
|
+ pageToken=marker)
|
|
|
|
|
+ .execute())
|
|
|
|
|
+ if 'error' in response:
|
|
|
|
|
+ return ServerPagedResultList(False, None, False, data=[])
|
|
|
|
|
+ objects = []
|
|
|
|
|
+ for obj in response.get('items', []):
|
|
|
|
|
+ objects.append(GCSObject(self._provider, self, obj))
|
|
|
|
|
+ if len(objects) > max_result:
|
|
|
|
|
+ cb.log.warning('Expected at most %d results; got %d',
|
|
|
|
|
+ max_result, len(objects))
|
|
|
|
|
+ return ServerPagedResultList('nextPageToken' in response,
|
|
|
|
|
+ response.get('nextPageToken'),
|
|
|
|
|
+ False, data=objects)
|
|
|
|
|
+ except:
|
|
|
|
|
+ return ServerPagedResultList(False, None, False, data=[])
|
|
|
|
|
+
|
|
|
|
|
+ def delete(self, delete_contents=False):
|
|
|
|
|
+ """
|
|
|
|
|
+ Delete this bucket.
|
|
|
|
|
+ """
|
|
|
|
|
+ (self._provider
|
|
|
|
|
+ .gcp_storage
|
|
|
|
|
+ .buckets()
|
|
|
|
|
+ .delete(bucket=self.name)
|
|
|
|
|
+ .execute())
|
|
|
|
|
+
|
|
|
|
|
+ def create_object(self, name):
|
|
|
|
|
+ """
|
|
|
|
|
+ Create an empty plain text object.
|
|
|
|
|
+ """
|
|
|
|
|
+ response = self.create_object_with_media_body(
|
|
|
|
|
+ name,
|
|
|
|
|
+ googleapiclient.http.MediaIoBaseUpload(
|
|
|
|
|
+ io.BytesIO(''), mimetype='plain/text'))
|
|
|
|
|
+ return GCSObject(self._provider, self, response) if response else None
|
|
|
|
|
+
|
|
|
|
|
+ def create_object_with_media_body(self, name, media_body):
|
|
|
|
|
+ try:
|
|
|
|
|
+ response = (self._provider
|
|
|
|
|
+ .gcp_storage
|
|
|
|
|
+ .objects()
|
|
|
|
|
+ .insert(bucket=self.name,
|
|
|
|
|
+ body={'name': name},
|
|
|
|
|
+ media_body=media_body)
|
|
|
|
|
+ .execute())
|
|
|
|
|
+ if 'error' in response:
|
|
|
|
|
+ return None
|
|
|
|
|
+ return response
|
|
|
|
|
+ except:
|
|
|
|
|
+ return None
|