def set_user_gl_name(self, id, gl_name): self.__insert_user(id) try: with self.__conn: self.__conn.execute( 'update users set gl_name = ? where id = ?', (gl_name, id)) except sqlite3.IntegrityError: # Assume duplicate gl_name if (conflicting_id := self.try_user_id_from_gl_name(gl_name)) is not None: raise common.Error( f'That name is already taken by <@{conflicting_id}>.') raise common.Error('Someone else has taken that name already.')
def get_or_create_net(prop, name, resources, gw_dependencies, private_google_access=False, create_firewall=False): net_cidr = prop.get(name + '-cidr') if net_cidr: net_name = '{}-{}'.format(prop['deployment'][:22], name) subnet_name = '{}-subnet'.format(net_name) net = make_net(net_name) subnet = make_subnet( prop, subnet_name, net_name, net_cidr, private_google_access) resources += [net, subnet] gw_dependencies.append(subnet_name) else: net_name = prop.get(name + '-name') subnet_name = prop.get(name + '-subnetwork-name') if not subnet_name: raise common.Error( 'Network {} is missing.'.format(net_name.split('-'))) if create_firewall: firewall_rules = create_firewall_rules(prop, name, net_name, net_cidr) if firewall_rules: resources.extend(firewall_rules) return net_name, subnet_name
def GenerateMultipleComputeVMs(context): """Generates multiple VMs that are copies of a single VM spec.""" prop = context.properties if VM_COPIES not in prop: raise common.Error('%s property is needed for multiple VM generation' % VM_COPIES) use_endpoint = ENDPOINT_NAME in prop n_of_copies = prop[VM_COPIES] resources = [] new_disks = [] for idx in range(1, n_of_copies + 1): ctx = copy.deepcopy(context) idx_prop = ctx.properties ctx.env[default.NAME] += AddIdx(idx) # Do something with the instance name and with the disk names disk_prefix = ctx.env[default.NAME] if default.INSTANCE_NAME in idx_prop: idx_prop[default.INSTANCE_NAME] += AddIdx(idx) disk_prefix = idx_prop[default.INSTANCE_NAME] if default.DISKS in idx_prop: # Modifies the disks in idx_prop to have a unique name # Adding the vm extension to match the final hostname NameTheDisks(idx_prop[default.DISKS], disk_prefix) if use_endpoint: idx_prop[ENDPOINT_NAME] += AddIdx(idx) resources += vm_instance.GenerateComputeVM(ctx) resources += vm_instance.AddServiceEndpointIfNeeded(ctx) new_disks += common.AddDiskResourcesIfNeeded(ctx) AddDisksToContext(context, new_disks) return resources
def validate_region(test_zone, valid_region): test_region = common.ZoneToRegion(test_zone) if test_region != valid_region: err_msg = '{} is in region {}. All subnets must be ' + \ 'in the same region ({})' raise common.Error(err_msg.format(test_zone, test_region, valid_region))
def get_user_gl_name(self, id): for row in self.__conn.execute( 'select gl_name from users where id = ?', (id, )): if row[0] is not None: return row[0] raise common.Error( f'I don\'t know what name <@{id}> goes by in the GL spreadsheet. ' f'<@{id}> please tell me your name with **!iam Whoever**.')
def _get_locs(rows): locs = {field.name: _Loc(field) for field in _fields} cont_loc = None for col, heading in enumerate(rows[_heading_row]): if heading: cont_loc = None for loc in locs.values(): heading_re = loc.field.heading_re if heading_re.search(heading): if loc.begin_col is not None: raise common.Error( f'I found multiple headings matching "{heading_re.pattern}" in the GL spreadsheet.') loc.begin_col = col loc.end_col = col + 1 if loc.field.sub_heading_row is not None: cont_loc = loc break elif cont_loc is not None: if rows[cont_loc.field.sub_heading_row][col]: cont_loc.end_col = col + 1 else: cont_loc = None for loc in locs.values(): if loc.begin_col is None: raise common.Error( f'I couldn\'t find a heading matching "{loc.field.heading_re.pattern}" in the GL spreadsheet.') if loc.field.sub_heading_row is not None: loc.sub_headings = rows[loc.field.sub_heading_row][loc.begin_col:loc.end_col] seen = set() for sub_heading in loc.sub_headings: if sub_heading in seen: raise common.Error( 'There are multiple columns in the GL spreadsheet under ' f'{rows[_heading_row][loc.begin_col]} with the same ' f'sub-heading ({sub_heading}).') seen.add(sub_heading) return locs
def GenerateDisks(context, disk_list, new_disks): """Generates as many disks as passed in the disk_list.""" project = context.env[default.PROJECT] prop = context.properties zone = prop.setdefault(ZONE, DEFAULT_ZONE) sourced_disks = [] disk_names = [] for disk in disk_list: d_name = (disk[default.DEVICE_NAME] if default.DISK_NAME not in disk else disk[default.DISK_NAME]) if default.DISK_SOURCE in disk: # Existing disk, expect disk api link source = disk[default.DISK_SOURCE] else: # The disks should be create separately if default.DEVICE_NAME not in disk and default.DISK_NAME not in disk: raise common.Error( 'deviceName or diskName is needed for each disk in ' 'this module implemention of multiple disks per vm.') disk_init = disk.setdefault(default.INITIALIZEP, dict()) disk_size = disk_init.setdefault(default.DISK_SIZE, DEFAULT_DATADISKSIZE) passed_disk_type = disk_init.setdefault(default.TYPE, DEFAULT_DISKTYPE) disk_type = common.LocalComputeLink(project, zone, 'diskTypes', passed_disk_type) new_disks.append({ 'name': d_name, 'type': default.DISK, 'properties': { 'type': disk_type, 'sizeGb': disk_size, 'zone': zone } }) # pyformat: disable disk_names.append(d_name) source = common.Ref(d_name) sourced_disks.append({ 'deviceName': d_name, 'autoDelete': True, 'boot': False, 'source': source, 'type': DEFAULT_PERSISTENT, }) items = prop[METADATA].setdefault('items', list()) items.append({'key': ATTACHED_DISKS, 'value': ','.join(disk_names)}) return sourced_disks, new_disks
def GenerateDisks(context, disk_list, new_disks): """Generates as many disks as passed in the disk_list.""" prop = context.properties zone = prop.setdefault(ZONE, DEFAULT_ZONE) sourced_disks = [] disk_names = [] for disk in disk_list: if default.DISK_SOURCE in disk or disk[default.TYPE] == SCRATCH: # These disks do not need to be created as separate resources sourced_disks.append(disk) else: # Extract disk parameters and create as separate resource disk_init = disk[default.INITIALIZEP] if default.DEVICE_NAME in disk: d_name = disk[default.DEVICE_NAME] elif default.DISK_NAME in disk_init: d_name = disk_init[default.DISK_NAME] else: raise common.Error( 'deviceName or diskName is needed for each disk in ' 'this module implemention of multiple disks per vm.') new_disks.append({ 'name': d_name, 'type': default.DISK, 'properties': { 'type': disk_init[default.DISKTYPE], 'sizeGb': disk_init[default.DISK_SIZE], 'zone': zone } }) disk_names.append(d_name) source = common.Ref(d_name) sourced_disks.append({ 'deviceName': d_name, 'autoDelete': disk[default.AUTO_DELETE], 'boot': False, 'source': source, 'type': disk[default.TYPE], }) items = prop[METADATA].setdefault('items', list()) items.append({'key': ATTACHED_DISKS, 'value': ','.join(disk_names)}) return sourced_disks, new_disks
def GenerateDisks(context, disk_list, new_disks): """Generates as many disks as passed in the disk_list.""" prop = context.properties zone = prop.setdefault(ZONE, DEFAULT_ZONE) sourced_disks = [] disk_names = [] for disk in disk_list: if default.DISK_SOURCE in disk or disk[default.TYPE] == SCRATCH: # These disks do not need to be created as separate resources sourced_disks.append(disk) else: # Extract disk parameters and create as separate resource disk_init = disk[default.INITIALIZEP] if default.DEVICE_NAME in disk: d_name = disk[default.DEVICE_NAME] elif default.DISK_NAME in disk_init: d_name = disk_init[default.DISK_NAME] else: raise common.Error( "deviceName or diskName is needed for each disk in " "this module implemention of multiple disks per vm.") new_disks.append({ "name": d_name, "type": default.DISK, "properties": { "type": disk_init[default.DISKTYPE], "sizeGb": disk_init[default.DISK_SIZE], "zone": zone, }, }) disk_names.append(d_name) source = common.Ref(d_name) sourced_disks.append({ "deviceName": d_name, "autoDelete": disk[default.AUTO_DELETE], "boot": False, "source": source, "type": disk[default.TYPE], }) items = prop[METADATA].setdefault("items", list()) items.append({"key": ATTACHED_DISKS, "value": ",".join(disk_names)}) return sourced_disks, new_disks
def GetNetworkInterfaces(context): """Extracts the network interfaces to be used in the VM creation.""" props = context.properties networks = props.setdefault(NETWORKS, DEFAULT_NETWORKS) subnetworks = props.get(SUBNETWORKS, []) external_ips = props.get(EXTERNAL_IPS, DEFAULT_EXTERNAL_IPS) network_interfaces = [] for i in range(len(networks)): name = 'Interface %d' % i network_interface = { 'network': common.MakeNetworkComputeLink(context, networks[i]), 'name': name, } if subnetworks and i < len(subnetworks) and subnetworks[i]: network_interface['subnetwork'] = common.MakeSubnetworkComputeLink( context, subnetworks[i]) ip_value = external_ips[i] if i < len(external_ips) else 'NONE' is_static_ip = VALID_IP_RE.match(ip_value) is not None if ip_value != 'EPHEMERAL' and ip_value != 'NONE' and not is_static_ip: raise common.Error( ('External IP value "%s" is invalid. Valid values ' 'are: a valid IP Address, EPHEMERAL or NONE.') % ip_value) if ip_value == 'EPHEMERAL' or is_static_ip: access_config = { 'name': '%s %s' % (name, default.EXTERNAL), 'type': default.ONE_NAT, } if is_static_ip: access_config[default.NAT_IP] = ip_value network_interface['accessConfigs'] = [access_config] network_interfaces.append(network_interface) return network_interfaces
def gather_messages(MessageClass, tcpdir): ''' Attempts to construct a series of MessageClass objects from the data. The basic idea comes from pyper's function, HTTPFlow.analyze.gather_messages. Args: * MessageClass = class, Request or Response * tcpdir = TCPDirection, from which will be extracted the data Returns: [MessageClass] If the first message fails to construct, the flow is considered to be invalid. After that, all messages are stored and returned. The end of the data is an invalid message. This is designed to handle partially valid HTTP flows semi-gracefully: if the flow is bad, the application probably bailed on it after that anyway. ''' messages = [] # [MessageClass] pointer = 0 # starting index of data that MessageClass should look at # while there's data left while pointer < len(tcpdir.data): curr_data = tcpdir.data[pointer:pointer + 200] # debug var try: msg = MessageClass(tcpdir, pointer) except (dpkt.Error, ): # if the message failed error = sys.exc_info()[1] if pointer == 0: # if this is the first message raise http.Error('Invalid http') else: # we're done parsing messages logging.warning("We got a dpkt.Error %s, but we are done." % error) break # out of the loop except: raise # ok, all good messages.append(msg) pointer += msg.data_consumed return messages
def GenerateComputeVM(context): """Generates one VM instance resource.""" name = context.env['name'] prop = context.properties if SRCIMAGE not in prop: raise common.Error('"%s" is a mandatory property' % SRCIMAGE) boot_disk_type = prop.setdefault(BOOTDISKTYPE, DEFAULT_DISKTYPE) prop[default.DISKTYPE] = boot_disk_type can_ip_fwd = prop.setdefault(CAN_IP_FWD, DEFAULT_IP_FWD) disks = prop.setdefault(default.DISKS, list()) # Temporary alternative while multiple disks on creation is not allowed if disks: new_disks = prop.setdefault(default.DISK_RESOURCES, list()) disks, prop[DISK_RESOURCES] = GenerateDisks(context, disks, new_disks) machine_type = prop.setdefault(MACHINETYPE, DEFAULT_MACHINETYPE) metadata = prop.setdefault(METADATA, dict()) network = prop.setdefault(NETWORK, DEFAULT_NETWORK) named = INSTANCE_NAME in prop provide_boot = prop.setdefault(PROVIDE_BOOT, DEFAULT_PROVIDE_BOOT) tags = prop.setdefault(TAGS, dict([('items', [])])) vm_name = prop[INSTANCE_NAME] if named else common.AutoName( name, default.INSTANCE) zone = prop.setdefault(ZONE, DEFAULT_ZONE) if provide_boot: dev_mode = DEVIMAGE in prop and prop[DEVIMAGE] src_image = common.MakeC2DImageLink(prop[SRCIMAGE], dev_mode) boot_name = common.AutoName(context.env['name'], default.DISK, 'boot') disk_size = (prop[BOOTDISKSIZE] if BOOTDISKSIZE in prop else DEFAULT_BOOTDISKSIZE) disk_type = common.MakeLocalComputeLink(context, default.DISKTYPE) disks = PrependBootDisk(disks, boot_name, disk_type, disk_size, src_image) machine_type = common.MakeLocalComputeLink(context, default.MACHINETYPE) network = common.MakeGlobalComputeLink(context, default.NETWORK) # To be consistent with Dev console and gcloud, service accounts need to be # explicitly disabled remove_scopes = prop[NO_SCOPE] if NO_SCOPE in prop else False if remove_scopes and SERVICE_ACCOUNTS in prop: prop.pop(SERVICE_ACCOUNTS) else: # Make sure there is a default service account prop.setdefault(SERVICE_ACCOUNTS, copy.deepcopy(DEFAULT_SERVICE_ACCOUNT)) # pyformat: disable resource = [{ 'name': vm_name, 'type': default.INSTANCE, 'properties': { 'zone': zone, 'machineType': machine_type, 'canIpForward': can_ip_fwd, 'disks': disks, 'networkInterfaces': [{ 'network': network, 'accessConfigs': [{ 'name': default.EXTERNAL, 'type': default.ONE_NAT }] }], 'tags': tags, 'metadata': metadata, } }] # pyformat: enable # Pass through any additional property to the VM if SERVICE_ACCOUNTS in prop: resource[0]['properties'].update( {SERVICE_ACCOUNTS: prop[SERVICE_ACCOUNTS]}) return resource
def ReadBytes(self, length): if self.offset + length > len(self.data): raise common.Error('Bad IPS file.') result = self.data[self.offset:self.offset + length] self.offset += length return result
def __init__(self, data): self.data = data if self.data[:5] != b'PATCH': raise common.Error('Bad IPS file.') self.offset = 5
def validate_same_region(zone_a, zone_b): if not common.ZoneToRegion(zone_a) == common.ZoneToRegion(zone_b): raise common.Error('Member A Zone ({}) and Member B Zone ({}) ' 'are not in the same region'.format(zone_a, zone_b))
def validate_networks(internal, external): if external == internal: err_msg = 'Each network must be different, ' + \ 'but both External and Internal networks are set to {}' raise common.Error(err_msg.format(external))
def GenerateDisks(context, disk_list, new_disks): """Generates as many disks as passed in the disk_list.""" project = context.env[default.PROJECT] prop = context.properties zone = prop.setdefault(ZONE, DEFAULT_ZONE) sourced_disks = [] disk_names = [] for disk in disk_list: d_name = (disk[default.DEVICE_NAME] if default.DISK_NAME not in disk else disk[default.DISK_NAME]) d_autodelete = (True if default.AUTO_DELETE not in disk else disk[default.AUTO_DELETE]) d_type = (DEFAULT_PERSISTENT if default.TYPE not in disk else disk[default.TYPE]) if default.DISK_SOURCE in disk: # Existing disk, expect disk api link source = disk[default.DISK_SOURCE] elif d_type == SCRATCH: # No special treatment needed for SSD disk if default.INITIALIZEP in disk: disk_type = disk[default.INITIALIZEP][DISKTYPE] else: disk_type = 'local-ssd' disk[default.INITIALIZEP] = { DISKTYPE: common.LocalComputeLink(project, zone, 'diskTypes', disk_type) } sourced_disks.append(disk) continue else: if default.DEVICE_NAME not in disk and default.DISK_NAME not in disk: raise common.Error( 'deviceName or diskName is needed for each disk in ' 'this module implemention of multiple disks per vm.') # In the Instance API reference, size and type are within this property if default.INITIALIZEP in disk: disk_init = disk[default.INITIALIZEP] disk_size = disk_init.setdefault(default.DISK_SIZE, DEFAULT_DATADISKSIZE) passed_disk_type = disk_init.setdefault( DISKTYPE, DEFAULT_DISKTYPE) # You can also simply pass the size and type properties directly else: disk_size = disk.setdefault(default.DISK_SIZE, DEFAULT_DATADISKSIZE) passed_disk_type = disk.setdefault(DISKTYPE, DEFAULT_DISKTYPE) disk_type = common.LocalComputeLink(project, zone, 'diskTypes', passed_disk_type) new_disks.append({ 'name': d_name, 'type': default.DISK, 'properties': { 'type': disk_type, 'sizeGb': disk_size, 'zone': zone } }) # pyformat: disable disk_names.append(d_name) source = common.Ref(d_name) sourced_disks.append({ 'deviceName': d_name, 'autoDelete': d_autodelete, 'boot': False, 'source': source, 'type': d_type, }) items = prop[METADATA].setdefault('items', list()) items.append({'key': ATTACHED_DISKS, 'value': ','.join(disk_names)}) return sourced_disks, new_disks
def GenerateComputeVM(context, create_disks_separately=True): """Generates one VM instance resource. Args: context: Template context dictionary. create_disks_separately: When true (default), all new disk resources are created as separate resources. This is legacy behaviour from when multiple disks creation was not allowed in the disks property. Returns: dictionary representing instance resource. """ prop = context.properties boot_disk_type = prop.setdefault(BOOTDISKTYPE, DEFAULT_DISKTYPE) prop[default.DISKTYPE] = boot_disk_type can_ip_fwd = prop.setdefault(CAN_IP_FWD, DEFAULT_IP_FWD) disks = prop.setdefault(default.DISKS, list()) local_ssd = prop.setdefault(default.LOCAL_SSD, 0) if disks: if create_disks_separately: # Legacy alternative from when multiple disks on creation were not allowed new_disks = prop.setdefault(default.DISK_RESOURCES, list()) SetDiskProperties(context, disks) disks, prop[DISK_RESOURCES] = GenerateDisks(context, disks, new_disks) else: # All new disks (except local ssd) must provide a sourceImage or existing # source. Add blank source image if non provided. SetDiskProperties(context, disks, add_blank_src_img=True) machine_type = prop.setdefault(MACHINETYPE, DEFAULT_MACHINETYPE) metadata = prop.setdefault(METADATA, dict()) SetMetadataDefaults(metadata) network = prop.setdefault(NETWORK, DEFAULT_NETWORK) vm_name = MakeVMName(context) provide_boot = prop.setdefault(PROVIDE_BOOT, DEFAULT_PROVIDE_BOOT) tags = prop.setdefault(TAGS, dict([('items', [])])) zone = prop.setdefault(ZONE, DEFAULT_ZONE) has_external_ip = prop.get(HAS_EXTERNAL_IP, DEFAULT_HAS_EXTERNAL_IP) static_ip = prop.get(STATIC_IP, DEFAULT_STATIC_IP) nat_ip = prop.get(NAT_IP, None) if provide_boot: dev_mode = DEVIMAGE in prop and prop[DEVIMAGE] src_image = common.MakeC2DImageLink(prop[SRCIMAGE], dev_mode) boot_name = common.AutoName(context.env['name'], default.DISK, 'boot') disk_size = prop.get(BOOTDISKSIZE, DEFAULT_BOOTDISKSIZE) disk_type = common.MakeLocalComputeLink(context, DISKTYPE) autodelete = prop.get(AUTODELETE_BOOTDISK, DEFAULT_AUTODELETE_BOOTDISK) disks = PrependBootDisk(disks, boot_name, disk_type, disk_size, src_image, autodelete) if local_ssd: disks = AppendLocalSSDDisks(context, disks, local_ssd) machine_type = common.MakeLocalComputeLink(context, default.MACHINETYPE) network = common.MakeGlobalComputeLink(context, default.NETWORK) subnetwork = '' if default.SUBNETWORK in prop: subnetwork = common.MakeSubnetworkComputeLink(context, default.SUBNETWORK) # To be consistent with Dev console and gcloud, service accounts need to be # explicitly disabled remove_scopes = prop[NO_SCOPE] if NO_SCOPE in prop else False if remove_scopes and SERVICE_ACCOUNTS in prop: prop.pop(SERVICE_ACCOUNTS) else: # Make sure there is a default service account prop.setdefault(SERVICE_ACCOUNTS, copy.deepcopy(DEFAULT_SERVICE_ACCOUNT)) resource = [] access_configs = [] if has_external_ip: access_config = {'name': default.EXTERNAL, 'type': default.ONE_NAT} access_configs.append(access_config) if static_ip and nat_ip: raise common.Error( 'staticIP=True and natIP cannot be specified at the same time') if static_ip: address_resource, nat_ip = MakeStaticAddress(vm_name, zone) resource.append(address_resource) if nat_ip: access_config['natIP'] = nat_ip else: if static_ip: raise common.Error('staticIP cannot be True when hasExternalIP is False') if nat_ip: raise common.Error( 'natIP must not be specified when hasExternalIP is False') network_interfaces = [] if subnetwork: network_interfaces.insert(0, { 'network': network, 'subnetwork': subnetwork, 'accessConfigs': access_configs }) else: network_interfaces.insert(0, { 'network': network, 'accessConfigs': access_configs }) resource.insert(0, { 'name': vm_name, 'type': default.INSTANCE, 'properties': { 'zone': zone, 'machineType': machine_type, 'canIpForward': can_ip_fwd, 'disks': disks, 'networkInterfaces': network_interfaces, 'tags': tags, 'metadata': metadata, } }) # Pass through any additional properties to the VM if SERVICE_ACCOUNTS in prop: resource[0]['properties'].update({SERVICE_ACCOUNTS: prop[SERVICE_ACCOUNTS]}) if GUEST_ACCELERATORS in prop: for accelerators in prop[GUEST_ACCELERATORS]: accelerators['acceleratorType'] = common.MakeAcceleratorTypeLink( context, accelerators['acceleratorType']) resource[0]['properties'].update( {GUEST_ACCELERATORS: prop[GUEST_ACCELERATORS]}) # GPUs cannot be attached to live migratable instances. See: # https://cloud.google.com/compute/docs/gpus/#restrictions resource[0]['properties'].update( {'scheduling': {'onHostMaintenance': 'terminate'}}) return resource
def GenerateComputeVM(context): """Generates one VM instance resource.""" prop = context.properties boot_disk_type = prop.setdefault(BOOTDISKTYPE, DEFAULT_DISKTYPE) prop[default.DISKTYPE] = boot_disk_type can_ip_fwd = prop.setdefault(CAN_IP_FWD, DEFAULT_IP_FWD) disks = prop.setdefault(default.DISKS, list()) local_ssd = prop.setdefault(default.LOCAL_SSD, 0) # Temporary alternative while multiple disks on creation is not allowed if disks: new_disks = prop.setdefault(default.DISK_RESOURCES, list()) disks, prop[DISK_RESOURCES] = GenerateDisks(context, disks, new_disks) machine_type = prop.setdefault(MACHINETYPE, DEFAULT_MACHINETYPE) metadata = prop.setdefault(METADATA, dict()) network = prop.setdefault(NETWORK, DEFAULT_NETWORK) vm_name = MakeVMName(context) provide_boot = prop.setdefault(PROVIDE_BOOT, DEFAULT_PROVIDE_BOOT) tags = prop.setdefault(TAGS, dict([('items', [])])) zone = prop.setdefault(ZONE, DEFAULT_ZONE) has_external_ip = prop.get(HAS_EXTERNAL_IP, DEFAULT_HAS_EXTERNAL_IP) static_ip = prop.get(STATIC_IP, DEFAULT_STATIC_IP) nat_ip = prop.get(NAT_IP, None) if provide_boot: dev_mode = DEVIMAGE in prop and prop[DEVIMAGE] src_image = common.MakeC2DImageLink(prop[SRCIMAGE], dev_mode) boot_name = common.AutoName(context.env['name'], default.DISK, 'boot') disk_size = prop.get(BOOTDISKSIZE, DEFAULT_BOOTDISKSIZE) disk_type = common.MakeLocalComputeLink(context, DISKTYPE) autodelete = prop.get(AUTODELETE_BOOTDISK, DEFAULT_AUTODELETE_BOOTDISK) disks = PrependBootDisk(disks, boot_name, disk_type, disk_size, src_image, autodelete) if local_ssd: disks = AppendLocalSSDDisks(context, disks, local_ssd) machine_type = common.MakeLocalComputeLink(context, default.MACHINETYPE) network = common.MakeGlobalComputeLink(context, default.NETWORK) subnetwork = '' if default.SUBNETWORK in prop: subnetwork = common.MakeSubnetworkComputeLink(context, default.SUBNETWORK) # To be consistent with Dev console and gcloud, service accounts need to be # explicitly disabled remove_scopes = prop[NO_SCOPE] if NO_SCOPE in prop else False if remove_scopes and SERVICE_ACCOUNTS in prop: prop.pop(SERVICE_ACCOUNTS) else: # Make sure there is a default service account prop.setdefault(SERVICE_ACCOUNTS, copy.deepcopy(DEFAULT_SERVICE_ACCOUNT)) resource = [] access_configs = [] if has_external_ip: access_config = {'name': default.EXTERNAL, 'type': default.ONE_NAT} access_configs.append(access_config) if static_ip and nat_ip: raise common.Error( 'staticIP=True and natIP cannot be specified at the same time') if static_ip: address_resource, nat_ip = MakeStaticAddress(vm_name, zone) resource.append(address_resource) if nat_ip: access_config['natIP'] = nat_ip else: if static_ip: raise common.Error( 'staticIP cannot be True when hasExternalIP is False') if nat_ip: raise common.Error( 'natIP must not be specified when hasExternalIP is False') network_interfaces = [] if subnetwork: network_interfaces.insert( 0, { 'network': network, 'subnetwork': subnetwork, 'accessConfigs': access_configs }) else: network_interfaces.insert(0, { 'network': network, 'accessConfigs': access_configs }) resource.insert( 0, { 'name': vm_name, 'type': default.INSTANCE, 'properties': { 'zone': zone, 'machineType': machine_type, 'canIpForward': can_ip_fwd, 'disks': disks, 'networkInterfaces': network_interfaces, 'tags': tags, 'metadata': metadata, } }) # Pass through any additional property to the VM if SERVICE_ACCOUNTS in prop: resource[0]['properties'].update( {SERVICE_ACCOUNTS: prop[SERVICE_ACCOUNTS]}) return resource