Merge "Azure: Handle IPv6"
This commit is contained in:
commit
8ee837670e
|
@ -24,10 +24,11 @@ from . import azul
|
|||
|
||||
|
||||
class AzureInstance(statemachine.Instance):
|
||||
def __init__(self, vm, nic=None, pip=None):
|
||||
def __init__(self, vm, nic=None, pip4=None, pip6=None):
|
||||
self.external_id = vm['name']
|
||||
self.metadata = vm['tags'] or {}
|
||||
self.private_ipv4 = None
|
||||
self.private_ipv6 = None
|
||||
self.public_ipv4 = None
|
||||
self.public_ipv6 = None
|
||||
|
||||
|
@ -36,12 +37,17 @@ class AzureInstance(statemachine.Instance):
|
|||
ip_config_prop = ip_config_data['properties']
|
||||
if ip_config_prop['privateIPAddressVersion'] == 'IPv4':
|
||||
self.private_ipv4 = ip_config_prop['privateIPAddress']
|
||||
if ip_config_prop['privateIPAddressVersion'] == 'IPv6':
|
||||
self.private_ipv6 = ip_config_prop['privateIPAddress']
|
||||
# public_ipv6
|
||||
|
||||
if pip:
|
||||
self.public_ipv4 = pip['properties'].get('ipAddress')
|
||||
if pip4:
|
||||
self.public_ipv4 = pip4['properties'].get('ipAddress')
|
||||
if pip6:
|
||||
self.public_ipv6 = pip6['properties'].get('ipAddress')
|
||||
|
||||
self.interface_ip = self.public_ipv4 or self.private_ipv4
|
||||
self.interface_ip = (self.public_ipv4 or self.public_ipv6 or
|
||||
self.private_ipv4 or self.private_ipv6)
|
||||
self.region = vm['location']
|
||||
self.az = ''
|
||||
|
||||
|
@ -58,6 +64,9 @@ class AzureDeleteStateMachine(statemachine.StateMachine):
|
|||
self.adapter = adapter
|
||||
self.external_id = external_id
|
||||
self.disk_names = []
|
||||
self.disks = []
|
||||
self.pip4 = None
|
||||
self.pip6 = None
|
||||
|
||||
def advance(self):
|
||||
if self.state == self.START:
|
||||
|
@ -78,13 +87,16 @@ class AzureDeleteStateMachine(statemachine.StateMachine):
|
|||
if self.state == self.NIC_DELETING:
|
||||
self.nic = self.adapter._refresh_delete(self.nic)
|
||||
if self.nic is None:
|
||||
self.pip = self.adapter._deletePublicIPAddress(
|
||||
self.external_id + '-nic-pip')
|
||||
self.pip4 = self.adapter._deletePublicIPAddress(
|
||||
self.external_id + '-pip-IPv4')
|
||||
self.pip6 = self.adapter._deletePublicIPAddress(
|
||||
self.external_id + '-pip-IPv6')
|
||||
self.state = self.PIP_DELETING
|
||||
|
||||
if self.state == self.PIP_DELETING:
|
||||
self.pip = self.adapter._refresh_delete(self.pip)
|
||||
if self.pip is None:
|
||||
self.pip4 = self.adapter._refresh_delete(self.pip4)
|
||||
self.pip6 = self.adapter._refresh_delete(self.pip6)
|
||||
if self.pip4 is None and self.pip6 is None:
|
||||
self.disks = []
|
||||
for name in self.disk_names:
|
||||
disk = self.adapter._deleteDisk(name)
|
||||
|
@ -119,25 +131,56 @@ class AzureCreateStateMachine(statemachine.StateMachine):
|
|||
self.tags.update(metadata)
|
||||
self.hostname = hostname
|
||||
self.label = label
|
||||
self.pip = None
|
||||
self.pip4 = None
|
||||
self.pip6 = None
|
||||
self.nic = None
|
||||
self.vm = None
|
||||
# There are two parameters for IP addresses: SKU and
|
||||
# allocation method. SKU is "basic" or "standard".
|
||||
# Allocation method is "static" or "dynamic". Between IPv4
|
||||
# and v6, SKUs cannot be mixed (the same sku must be used for
|
||||
# both protocols). The standard SKU only supports static
|
||||
# allocation. Static is cheaper than dynamic, but basic is
|
||||
# cheaper than standard. Also, dynamic is faster than static.
|
||||
# Therefore, if IPv6 is used at all, standard+static for
|
||||
# everything; otherwise basic+dynamic in an IPv4-only
|
||||
# situation.
|
||||
if label.pool.ipv6:
|
||||
self.ip_sku = 'Standard'
|
||||
self.ip_method = 'static'
|
||||
else:
|
||||
self.ip_sku = 'Basic'
|
||||
self.ip_method = 'dynamic'
|
||||
|
||||
def advance(self):
|
||||
if self.state == self.START:
|
||||
self.pip = self.adapter._createPublicIPAddress(
|
||||
self.tags, self.hostname)
|
||||
self.state = self.PIP_CREATING
|
||||
self.external_id = self.hostname
|
||||
if self.label.pool.public_ipv4:
|
||||
self.pip4 = self.adapter._createPublicIPAddress(
|
||||
self.tags, self.hostname, self.ip_sku, 'IPv4',
|
||||
self.ip_method)
|
||||
if self.label.pool.public_ipv6:
|
||||
self.pip6 = self.adapter._createPublicIPAddress(
|
||||
self.tags, self.hostname, self.ip_sku, 'IPv6',
|
||||
self.ip_method)
|
||||
self.state = self.PIP_CREATING
|
||||
|
||||
if self.state == self.PIP_CREATING:
|
||||
self.pip = self.adapter._refresh(self.pip)
|
||||
if self.adapter._succeeded(self.pip):
|
||||
self.nic = self.adapter._createNetworkInterface(
|
||||
self.tags, self.hostname, self.pip)
|
||||
self.state = self.NIC_CREATING
|
||||
else:
|
||||
return
|
||||
if self.pip4:
|
||||
self.pip4 = self.adapter._refresh(self.pip4)
|
||||
if not self.adapter._succeeded(self.pip4):
|
||||
return
|
||||
if self.pip6:
|
||||
self.pip6 = self.adapter._refresh(self.pip6)
|
||||
if not self.adapter._succeeded(self.pip6):
|
||||
return
|
||||
# At this point, every pip we have has succeeded (we may
|
||||
# have 0, 1, or 2).
|
||||
self.nic = self.adapter._createNetworkInterface(
|
||||
self.tags, self.hostname,
|
||||
self.label.pool.ipv4, self.label.pool.ipv6,
|
||||
self.pip4, self.pip6)
|
||||
self.state = self.NIC_CREATING
|
||||
|
||||
if self.state == self.NIC_CREATING:
|
||||
self.nic = self.adapter._refresh(self.nic)
|
||||
|
@ -163,20 +206,30 @@ class AzureCreateStateMachine(statemachine.StateMachine):
|
|||
|
||||
if self.state == self.NIC_QUERY:
|
||||
self.nic = self.adapter._refresh(self.nic, force=True)
|
||||
all_found = True
|
||||
for ip_config_data in self.nic['properties']['ipConfigurations']:
|
||||
ip_config_prop = ip_config_data['properties']
|
||||
if ip_config_prop['privateIPAddressVersion'] == 'IPv4':
|
||||
if 'privateIPAddress' in ip_config_prop:
|
||||
self.state = self.PIP_QUERY
|
||||
if 'privateIPAddress' not in ip_config_prop:
|
||||
all_found = False
|
||||
if all_found:
|
||||
self.state = self.PIP_QUERY
|
||||
|
||||
if self.state == self.PIP_QUERY:
|
||||
self.pip = self.adapter._refresh(self.pip, force=True)
|
||||
if 'ipAddress' in self.pip['properties']:
|
||||
all_found = True
|
||||
if self.pip4:
|
||||
self.pip4 = self.adapter._refresh(self.pip4, force=True)
|
||||
if 'ipAddress' not in self.pip4['properties']:
|
||||
all_found = False
|
||||
if self.pip6:
|
||||
self.pip6 = self.adapter._refresh(self.pip6, force=True)
|
||||
if 'ipAddress' not in self.pip6['properties']:
|
||||
all_found = False
|
||||
if all_found:
|
||||
self.state = self.COMPLETE
|
||||
|
||||
if self.state == self.COMPLETE:
|
||||
self.complete = True
|
||||
return AzureInstance(self.vm, self.nic, self.pip)
|
||||
return AzureInstance(self.vm, self.nic, self.pip4, self.pip6)
|
||||
|
||||
|
||||
class AzureAdapter(statemachine.Adapter):
|
||||
|
@ -283,17 +336,22 @@ class AzureAdapter(statemachine.Adapter):
|
|||
def _listPublicIPAddresses(self):
|
||||
return self.azul.public_ip_addresses.list(self.resource_group)
|
||||
|
||||
def _createPublicIPAddress(self, tags, hostname):
|
||||
def _createPublicIPAddress(self, tags, hostname, sku, version,
|
||||
allocation_method):
|
||||
v4_params_create = {
|
||||
'location': self.provider.location,
|
||||
'tags': tags,
|
||||
'sku': {
|
||||
'name': sku,
|
||||
},
|
||||
'properties': {
|
||||
'publicIpAllocationMethod': 'dynamic',
|
||||
'publicIpAddressVersion': version,
|
||||
'publicIpAllocationMethod': allocation_method,
|
||||
},
|
||||
}
|
||||
return self.azul.public_ip_addresses.create(
|
||||
self.resource_group,
|
||||
"%s-nic-pip" % hostname,
|
||||
"%s-pip-%s" % (hostname, version),
|
||||
v4_params_create,
|
||||
)
|
||||
|
||||
|
@ -310,37 +368,43 @@ class AzureAdapter(statemachine.Adapter):
|
|||
def _listNetworkInterfaces(self):
|
||||
return self.azul.network_interfaces.list(self.resource_group)
|
||||
|
||||
def _createNetworkInterface(self, tags, hostname, pip):
|
||||
def _createNetworkInterface(self, tags, hostname, ipv4, ipv6, pip4, pip6):
|
||||
|
||||
def make_ip_config(name, version, subnet_id, pip):
|
||||
ip_config = {
|
||||
'name': name,
|
||||
'properties': {
|
||||
'privateIpAddressVersion': version,
|
||||
'subnet': {
|
||||
'id': subnet_id
|
||||
},
|
||||
}
|
||||
}
|
||||
if pip:
|
||||
ip_config['properties']['publicIpAddress'] = {
|
||||
'id': pip['id']
|
||||
}
|
||||
return ip_config
|
||||
|
||||
ip_configs = []
|
||||
|
||||
if ipv4:
|
||||
ip_configs.append(make_ip_config('nodepool-v4-ip-config',
|
||||
'IPv4', self.provider.subnet_id,
|
||||
pip4))
|
||||
if ipv6:
|
||||
ip_configs.append(make_ip_config('nodepool-v6-ip-config',
|
||||
'IPv6', self.provider.subnet_id,
|
||||
pip6))
|
||||
|
||||
nic_data = {
|
||||
'location': self.provider.location,
|
||||
'tags': tags,
|
||||
'properties': {
|
||||
'ipConfigurations': [{
|
||||
'name': "nodepool-v4-ip-config",
|
||||
'properties': {
|
||||
'privateIpAddressVersion': 'IPv4',
|
||||
'subnet': {
|
||||
'id': self.provider.subnet_id
|
||||
},
|
||||
'publicIpAddress': {
|
||||
'id': pip['id']
|
||||
}
|
||||
}
|
||||
}]
|
||||
'ipConfigurations': ip_configs
|
||||
}
|
||||
}
|
||||
|
||||
if self.provider.ipv6:
|
||||
nic_data['properties']['ipConfigurations'].append({
|
||||
'name': "nodepool-v6-ip-config",
|
||||
'properties': {
|
||||
'privateIpAddressVersion': 'IPv6',
|
||||
'subnet': {
|
||||
'id': self.provider.subnet_id
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return self.azul.network_interfaces.create(
|
||||
self.resource_group,
|
||||
"%s-nic" % hostname,
|
||||
|
|
|
@ -114,9 +114,20 @@ class AzurePool(ConfigPool):
|
|||
def load(self, pool_config):
|
||||
self.name = pool_config['name']
|
||||
self.max_servers = pool_config['max-servers']
|
||||
self.use_internal_ip = bool(pool_config.get('use-internal-ip', False))
|
||||
self.host_key_checking = bool(pool_config.get(
|
||||
'host-key-checking', True))
|
||||
self.public_ipv4 = pool_config.get('public-ipv4',
|
||||
self.provider.public_ipv4)
|
||||
self.public_ipv6 = pool_config.get('public-ipv6',
|
||||
self.provider.public_ipv6)
|
||||
self.ipv4 = pool_config.get('ipv4', self.provider.ipv4)
|
||||
self.ipv6 = pool_config.get('ipv6', self.provider.ipv6)
|
||||
self.ipv4 = self.ipv4 or self.public_ipv4
|
||||
self.ipv6 = self.ipv6 or self.public_ipv6
|
||||
if not self.ipv4 or self.ipv6:
|
||||
self.ipv4 = True
|
||||
self.use_internal_ip = pool_config.get(
|
||||
'use-internal-ip', self.provider.use_internal_ip)
|
||||
self.host_key_checking = pool_config.get(
|
||||
'host-key-checking', self.provider.use_internal_ip)
|
||||
|
||||
@staticmethod
|
||||
def getSchema():
|
||||
|
@ -126,6 +137,12 @@ class AzurePool(ConfigPool):
|
|||
pool.update({
|
||||
v.Required('name'): str,
|
||||
v.Required('labels'): [azure_label],
|
||||
'ipv4': bool,
|
||||
'ipv6': bool,
|
||||
'public-ipv4': bool,
|
||||
'public-ipv6': bool,
|
||||
'use-internal-ip': bool,
|
||||
'host-key-checking': bool,
|
||||
})
|
||||
return pool
|
||||
|
||||
|
@ -157,8 +174,15 @@ class AzureProviderConfig(ProviderConfig):
|
|||
# TODO(corvus): remove
|
||||
self.zuul_public_key = self.provider['zuul-public-key']
|
||||
self.location = self.provider['location']
|
||||
self.subnet_id = self.provider['subnet-id']
|
||||
self.ipv6 = self.provider.get('ipv6', False)
|
||||
self.subnet_id = self.provider.get('subnet-id')
|
||||
# Don't use these directly; these are default values for
|
||||
# labels.
|
||||
self.public_ipv4 = self.provider.get('public-ipv4', False)
|
||||
self.public_ipv6 = self.provider.get('public-ipv6', False)
|
||||
self.ipv4 = self.provider.get('ipv4', None)
|
||||
self.ipv6 = self.provider.get('ipv6', None)
|
||||
self.use_internal_ip = self.provider.get('use-internal-ip', False)
|
||||
self.host_key_checking = self.provider.get('host-key-checking', True)
|
||||
self.resource_group = self.provider['resource-group']
|
||||
self.resource_group_location = self.provider['resource-group-location']
|
||||
self.auth_path = self.provider.get(
|
||||
|
@ -192,6 +216,12 @@ class AzureProviderConfig(ProviderConfig):
|
|||
v.Required('subnet-id'): str,
|
||||
v.Required('cloud-images'): [provider_cloud_images],
|
||||
v.Required('auth-path'): str,
|
||||
'ipv4': bool,
|
||||
'ipv6': bool,
|
||||
'public-ipv4': bool,
|
||||
'public-ipv6': bool,
|
||||
'use-internal-ip': bool,
|
||||
'host-key-checking': bool,
|
||||
})
|
||||
return v.Schema(provider)
|
||||
|
||||
|
|
|
@ -103,8 +103,9 @@ class StateMachineNodeLauncher(stats.StatsReporter):
|
|||
pool = self.handler.pool
|
||||
label = pool.labels[self.node.type[0]]
|
||||
|
||||
if pool.use_internal_ip and instance.private_ipv4:
|
||||
server_ip = instance.private_ipv4
|
||||
if (pool.use_internal_ip and
|
||||
(instance.private_ipv4 or instance.private_ipv6)):
|
||||
server_ip = instance.private_ipv4 or instance.private_ipv6
|
||||
else:
|
||||
server_ip = instance.interface_ip
|
||||
|
||||
|
@ -160,8 +161,9 @@ class StateMachineNodeLauncher(stats.StatsReporter):
|
|||
node.external_id = state_machine.external_id
|
||||
self.zk.storeNode(node)
|
||||
if state_machine.complete and not self.keyscan_future:
|
||||
self.log.debug("Submitting keyscan request")
|
||||
self.updateNodeFromInstance(instance)
|
||||
self.log.debug("Submitting keyscan request for %s",
|
||||
node.interface_ip)
|
||||
future = self.manager.keyscan_worker.submit(
|
||||
keyscan,
|
||||
node.id, node.interface_ip,
|
||||
|
@ -427,7 +429,6 @@ class StateMachineProvider(Provider, QuotaSupport):
|
|||
|
||||
def stop(self):
|
||||
self.log.debug("Stopping")
|
||||
self.running = False
|
||||
if self.state_machine_thread:
|
||||
while self.launchers or self.deleters:
|
||||
time.sleep(1)
|
||||
|
|
Loading…
Reference in New Issue