Add missing cloud/region/az/host_id info to nodes
To the greatest extent possible within the limitation of each provider, this adds cloud, region, az, and host_id to nodes. Each of AWS, Azure, GCE, IBMVPC have the cloud name hard-coded to a value that makes sense for each driver given that each of these are singleton clouds. Their region and az values are added as appropriate. The k8s, openshift, and openshiftpods all have their cloud names set to the k8s context name, which is the closest approximation of what the "cloud" attribute means in its existing usage in the OpenStack driver. If pods are launched, the host_id value is set to the k8s host node name, which is an approximation of the existing usage in the OpenStack driver (where it is typically an opaque uuid that uniquely identifies the hypervisor). Change-Id: I53765fc3914a84d2519f5d4dda4f8dc8feda72f2
This commit is contained in:
parent
36084ceb2d
commit
6d3b5f3bab
|
@ -82,7 +82,7 @@ CACHE_TTL = 10
|
||||||
|
|
||||||
|
|
||||||
class AwsInstance(statemachine.Instance):
|
class AwsInstance(statemachine.Instance):
|
||||||
def __init__(self, instance, quota):
|
def __init__(self, provider, instance, quota):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.external_id = instance.id
|
self.external_id = instance.id
|
||||||
self.metadata = tag_list_to_dict(instance.tags)
|
self.metadata = tag_list_to_dict(instance.tags)
|
||||||
|
@ -90,7 +90,9 @@ class AwsInstance(statemachine.Instance):
|
||||||
self.private_ipv6 = None
|
self.private_ipv6 = None
|
||||||
self.public_ipv4 = instance.public_ip_address
|
self.public_ipv4 = instance.public_ip_address
|
||||||
self.public_ipv6 = None
|
self.public_ipv6 = None
|
||||||
self.az = ''
|
self.cloud = 'AWS'
|
||||||
|
self.region = provider.region_name
|
||||||
|
self.az = instance.subnet.availability_zone
|
||||||
self.quota = quota
|
self.quota = quota
|
||||||
|
|
||||||
for iface in instance.network_interfaces[:1]:
|
for iface in instance.network_interfaces[:1]:
|
||||||
|
@ -206,7 +208,8 @@ class AwsCreateStateMachine(statemachine.StateMachine):
|
||||||
|
|
||||||
if self.state == self.COMPLETE:
|
if self.state == self.COMPLETE:
|
||||||
self.complete = True
|
self.complete = True
|
||||||
return AwsInstance(self.instance, self.quota)
|
return AwsInstance(self.adapter.provider, self.instance,
|
||||||
|
self.quota)
|
||||||
|
|
||||||
|
|
||||||
class AwsAdapter(statemachine.Adapter):
|
class AwsAdapter(statemachine.Adapter):
|
||||||
|
@ -357,7 +360,7 @@ class AwsAdapter(statemachine.Adapter):
|
||||||
if instance.state["Name"].lower() == "terminated":
|
if instance.state["Name"].lower() == "terminated":
|
||||||
continue
|
continue
|
||||||
quota = self._getQuotaForInstanceType(instance.instance_type)
|
quota = self._getQuotaForInstanceType(instance.instance_type)
|
||||||
yield AwsInstance(instance, quota)
|
yield AwsInstance(self.provider, instance, quota)
|
||||||
|
|
||||||
def getQuotaLimits(self):
|
def getQuotaLimits(self):
|
||||||
# Get the instance types that this provider handles
|
# Get the instance types that this provider handles
|
||||||
|
|
|
@ -84,8 +84,9 @@ class AzureInstance(statemachine.Instance):
|
||||||
|
|
||||||
self.interface_ip = (self.public_ipv4 or self.public_ipv6 or
|
self.interface_ip = (self.public_ipv4 or self.public_ipv6 or
|
||||||
self.private_ipv4 or self.private_ipv6)
|
self.private_ipv4 or self.private_ipv6)
|
||||||
|
self.cloud = 'Azure'
|
||||||
self.region = vm['location']
|
self.region = vm['location']
|
||||||
self.az = ''
|
self.az = vm['zones'][0]
|
||||||
|
|
||||||
def getQuotaInformation(self):
|
def getQuotaInformation(self):
|
||||||
return quota_info_from_sku(self.sku)
|
return quota_info_from_sku(self.sku)
|
||||||
|
|
|
@ -44,7 +44,10 @@ class GceInstance(statemachine.Instance):
|
||||||
def __init__(self, data, quota):
|
def __init__(self, data, quota):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.external_id = data['name']
|
self.external_id = data['name']
|
||||||
self.az = data['zone']
|
self.cloud = 'Google'
|
||||||
|
zone = data['zone'].rsplit('/', 1)[1]
|
||||||
|
self.region = zone.rsplit('-', 1)[0]
|
||||||
|
self.az = zone
|
||||||
|
|
||||||
iface = data.get('networkInterfaces', [])
|
iface = data.get('networkInterfaces', [])
|
||||||
if len(iface):
|
if len(iface):
|
||||||
|
|
|
@ -132,6 +132,7 @@ class IBMVPCInstance(statemachine.Instance):
|
||||||
self.public_ipv4 = fip['address']
|
self.public_ipv4 = fip['address']
|
||||||
|
|
||||||
self.interface_ip = self.public_ipv4 or self.private_ipv4
|
self.interface_ip = self.public_ipv4 or self.private_ipv4
|
||||||
|
self.cloud = 'IBM'
|
||||||
self.region = provider.region
|
self.region = provider.region
|
||||||
self.az = vm['zone']['name']
|
self.az = vm['zone']['name']
|
||||||
|
|
||||||
|
|
|
@ -47,10 +47,10 @@ class K8SLauncher(NodeLauncher):
|
||||||
else:
|
else:
|
||||||
self.node.connection_type = "kubectl"
|
self.node.connection_type = "kubectl"
|
||||||
self.node.interface_ip = resource['pod']
|
self.node.interface_ip = resource['pod']
|
||||||
pool = self.handler.provider.pools.get(self.node.pool)
|
pool = self.handler.provider.pools.get(self.node.pool)
|
||||||
resources = self.handler.manager.quotaNeededByLabel(
|
self.node.resources = self.handler.manager.quotaNeededByLabel(
|
||||||
self.node.type[0], pool)
|
self.node.type[0], pool).get_resources()
|
||||||
self.node.resources = resources.get_resources()
|
self.node.cloud = self.provider_config.context
|
||||||
self.zk.storeNode(self.node)
|
self.zk.storeNode(self.node)
|
||||||
self.log.info("Resource %s is ready" % resource['name'])
|
self.log.info("Resource %s is ready" % resource['name'])
|
||||||
|
|
||||||
|
|
|
@ -317,6 +317,7 @@ class KubernetesProvider(Provider, QuotaSupport):
|
||||||
"%s: pod failed to initialize (%s)" % (
|
"%s: pod failed to initialize (%s)" % (
|
||||||
namespace, pod.status.phase))
|
namespace, pod.status.phase))
|
||||||
resource["pod"] = label.name
|
resource["pod"] = label.name
|
||||||
|
node.host_id = pod.spec.node_name
|
||||||
return resource
|
return resource
|
||||||
|
|
||||||
def getRequestHandler(self, poolworker, request):
|
def getRequestHandler(self, poolworker, request):
|
||||||
|
|
|
@ -50,6 +50,7 @@ class OpenshiftLauncher(NodeLauncher):
|
||||||
self.node.shell_type = self.label.shell_type
|
self.node.shell_type = self.label.shell_type
|
||||||
# NOTE: resource access token may be encrypted here
|
# NOTE: resource access token may be encrypted here
|
||||||
self.node.connection_port = resource
|
self.node.connection_port = resource
|
||||||
|
self.node.cloud = self.provider_config.context
|
||||||
self.zk.storeNode(self.node)
|
self.zk.storeNode(self.node)
|
||||||
self.log.info("Resource %s is ready", project)
|
self.log.info("Resource %s is ready", project)
|
||||||
|
|
||||||
|
|
|
@ -257,6 +257,7 @@ class OpenshiftProvider(Provider, QuotaSupport):
|
||||||
raise exceptions.LaunchNodepoolException(
|
raise exceptions.LaunchNodepoolException(
|
||||||
"%s: pod failed to initialize (%s)" % (
|
"%s: pod failed to initialize (%s)" % (
|
||||||
project, pod.status.phase))
|
project, pod.status.phase))
|
||||||
|
return pod.spec.node_name
|
||||||
|
|
||||||
def getRequestHandler(self, poolworker, request):
|
def getRequestHandler(self, poolworker, request):
|
||||||
return handler.OpenshiftNodeRequestHandler(poolworker, request)
|
return handler.OpenshiftNodeRequestHandler(poolworker, request)
|
||||||
|
|
|
@ -30,7 +30,7 @@ class OpenshiftPodLauncher(OpenshiftLauncher):
|
||||||
self.node.interface_ip = pod_name
|
self.node.interface_ip = pod_name
|
||||||
self.zk.storeNode(self.node)
|
self.zk.storeNode(self.node)
|
||||||
|
|
||||||
self.handler.manager.waitForPod(project, pod_name)
|
pod_node_id = self.handler.manager.waitForPod(project, pod_name)
|
||||||
|
|
||||||
self.node.state = zk.READY
|
self.node.state = zk.READY
|
||||||
self.node.python_path = self.label.python_path
|
self.node.python_path = self.label.python_path
|
||||||
|
@ -47,6 +47,8 @@ class OpenshiftPodLauncher(OpenshiftLauncher):
|
||||||
'user': 'zuul-worker',
|
'user': 'zuul-worker',
|
||||||
}
|
}
|
||||||
self.node.connection_type = "kubectl"
|
self.node.connection_type = "kubectl"
|
||||||
|
self.node.cloud = self.provider_config.context
|
||||||
|
self.node.host_id = pod_node_id
|
||||||
self.zk.storeNode(self.node)
|
self.zk.storeNode(self.node)
|
||||||
self.log.info("Pod %s is ready" % self.node.external_id)
|
self.log.info("Pod %s is ready" % self.node.external_id)
|
||||||
|
|
||||||
|
|
|
@ -157,6 +157,7 @@ class StateMachineNodeLauncher(stats.StatsReporter):
|
||||||
node.public_ipv4 = instance.public_ipv4
|
node.public_ipv4 = instance.public_ipv4
|
||||||
node.private_ipv4 = instance.private_ipv4
|
node.private_ipv4 = instance.private_ipv4
|
||||||
node.public_ipv6 = instance.public_ipv6
|
node.public_ipv6 = instance.public_ipv6
|
||||||
|
node.cloud = instance.cloud
|
||||||
node.region = instance.region
|
node.region = instance.region
|
||||||
node.az = instance.az
|
node.az = instance.az
|
||||||
node.driver_data = instance.driver_data
|
node.driver_data = instance.driver_data
|
||||||
|
@ -737,6 +738,7 @@ class Instance:
|
||||||
* public_ipv4: str
|
* public_ipv4: str
|
||||||
* public_ipv6: str
|
* public_ipv6: str
|
||||||
* private_ipv4: str
|
* private_ipv4: str
|
||||||
|
* cloud: str
|
||||||
* az: str
|
* az: str
|
||||||
* region: str
|
* region: str
|
||||||
* driver_data: any
|
* driver_data: any
|
||||||
|
@ -759,6 +761,7 @@ class Instance:
|
||||||
self.public_ipv6 = None
|
self.public_ipv6 = None
|
||||||
self.private_ipv4 = None
|
self.private_ipv4 = None
|
||||||
self.interface_ip = None
|
self.interface_ip = None
|
||||||
|
self.cloud = None
|
||||||
self.az = None
|
self.az = None
|
||||||
self.region = None
|
self.region = None
|
||||||
self.metadata = {}
|
self.metadata = {}
|
||||||
|
|
|
@ -168,6 +168,7 @@ class VirtualMachinesCRUD(CRUDManager):
|
||||||
"networkProfile": data['properties']['networkProfile'],
|
"networkProfile": data['properties']['networkProfile'],
|
||||||
"provisioningState": "Creating"
|
"provisioningState": "Creating"
|
||||||
}
|
}
|
||||||
|
data['zones'] = ["1"]
|
||||||
self.items.append(data)
|
self.items.append(data)
|
||||||
disk_data = data.copy()
|
disk_data = data.copy()
|
||||||
disk_data['name'] = 'bionic-azure-' + str(uuid.uuid4())
|
disk_data['name'] = 'bionic-azure-' + str(uuid.uuid4())
|
||||||
|
|
|
@ -386,6 +386,10 @@ class TestDriverAws(tests.DBTestCase):
|
||||||
self.assertTrue(node.private_ipv4.startswith('203.0.113.'))
|
self.assertTrue(node.private_ipv4.startswith('203.0.113.'))
|
||||||
self.assertFalse(node.public_ipv4.startswith('203.0.113.'))
|
self.assertFalse(node.public_ipv4.startswith('203.0.113.'))
|
||||||
self.assertEqual(node.python_path, 'auto')
|
self.assertEqual(node.python_path, 'auto')
|
||||||
|
self.assertEqual(node.cloud, 'AWS')
|
||||||
|
self.assertEqual(node.region, 'us-west-2')
|
||||||
|
# Like us-west-2x where x is random
|
||||||
|
self.assertTrue(len(node.az) == len('us-west-2x'))
|
||||||
|
|
||||||
instance = self.ec2.Instance(node.external_id)
|
instance = self.ec2.Instance(node.external_id)
|
||||||
response = instance.describe_attribute(Attribute='ebsOptimized')
|
response = instance.describe_attribute(Attribute='ebsOptimized')
|
||||||
|
@ -498,10 +502,14 @@ class TestDriverAws(tests.DBTestCase):
|
||||||
instance.tags = []
|
instance.tags = []
|
||||||
instance.private_ip_address = '10.0.0.1'
|
instance.private_ip_address = '10.0.0.1'
|
||||||
instance.public_ip_address = '1.2.3.4'
|
instance.public_ip_address = '1.2.3.4'
|
||||||
|
instance.subnet = Dummy()
|
||||||
|
instance.subnet.availability_zone = 'us-west-2b'
|
||||||
iface = Dummy()
|
iface = Dummy()
|
||||||
iface.ipv6_addresses = [{'Ipv6Address': 'fe80::dead:beef'}]
|
iface.ipv6_addresses = [{'Ipv6Address': 'fe80::dead:beef'}]
|
||||||
instance.network_interfaces = [iface]
|
instance.network_interfaces = [iface]
|
||||||
awsi = AwsInstance(instance, None)
|
provider = Dummy()
|
||||||
|
provider.region_name = 'us-west-2'
|
||||||
|
awsi = AwsInstance(provider, instance, None)
|
||||||
self.assertEqual(awsi.public_ipv4, '1.2.3.4')
|
self.assertEqual(awsi.public_ipv4, '1.2.3.4')
|
||||||
self.assertEqual(awsi.private_ipv4, '10.0.0.1')
|
self.assertEqual(awsi.private_ipv4, '10.0.0.1')
|
||||||
self.assertEqual(awsi.public_ipv6, 'fe80::dead:beef')
|
self.assertEqual(awsi.public_ipv6, 'fe80::dead:beef')
|
||||||
|
|
|
@ -88,6 +88,9 @@ class TestDriverAzure(tests.DBTestCase):
|
||||||
{'key1': 'value1', 'key2': 'value2'})
|
{'key1': 'value1', 'key2': 'value2'})
|
||||||
self.assertEqual(node.host_keys, ['ssh-rsa FAKEKEY'])
|
self.assertEqual(node.host_keys, ['ssh-rsa FAKEKEY'])
|
||||||
self.assertEqual(node.python_path, 'auto')
|
self.assertEqual(node.python_path, 'auto')
|
||||||
|
self.assertEqual(node.cloud, 'Azure')
|
||||||
|
self.assertEqual(node.region, 'centralus')
|
||||||
|
self.assertEqual(node.az, '1')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.fake_azure.crud['Microsoft.Compute/virtualMachines'].
|
self.fake_azure.crud['Microsoft.Compute/virtualMachines'].
|
||||||
items[0]['properties']['osProfile']['customData'],
|
items[0]['properties']['osProfile']['customData'],
|
||||||
|
|
|
@ -303,6 +303,9 @@ class TestDriverGce(tests.DBTestCase):
|
||||||
self.assertEqual(node.connection_type, 'ssh')
|
self.assertEqual(node.connection_type, 'ssh')
|
||||||
self.assertEqual(node.attributes,
|
self.assertEqual(node.attributes,
|
||||||
{'key1': 'value1', 'key2': 'value2'})
|
{'key1': 'value1', 'key2': 'value2'})
|
||||||
|
self.assertEqual(node.cloud, 'Google')
|
||||||
|
self.assertEqual(node.region, 'us-central1')
|
||||||
|
self.assertEqual(node.az, 'us-central1-a')
|
||||||
if host_key_checking:
|
if host_key_checking:
|
||||||
nodescan.assert_called_with(
|
nodescan.assert_called_with(
|
||||||
node.interface_ip,
|
node.interface_ip,
|
||||||
|
|
|
@ -95,6 +95,9 @@ class TestDriverIBMVPC(tests.DBTestCase):
|
||||||
self.assertEqual(node.connection_type, 'ssh')
|
self.assertEqual(node.connection_type, 'ssh')
|
||||||
self.assertEqual(node.host_keys, [])
|
self.assertEqual(node.host_keys, [])
|
||||||
self.assertEqual(node.python_path, 'auto')
|
self.assertEqual(node.python_path, 'auto')
|
||||||
|
self.assertEqual(node.cloud, 'IBM')
|
||||||
|
self.assertEqual(node.region, 'us-south')
|
||||||
|
self.assertEqual(node.az, 'us-south-1')
|
||||||
|
|
||||||
node.state = zk.USED
|
node.state = zk.USED
|
||||||
self.zk.storeNode(node)
|
self.zk.storeNode(node)
|
||||||
|
|
|
@ -75,6 +75,9 @@ class FakeCoreClient(object):
|
||||||
class FakePod:
|
class FakePod:
|
||||||
class status:
|
class status:
|
||||||
phase = "Running"
|
phase = "Running"
|
||||||
|
|
||||||
|
class spec:
|
||||||
|
node_name = "k8s-default-pool-abcd-1234"
|
||||||
return FakePod
|
return FakePod
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,6 +127,8 @@ class TestDriverKubernetes(tests.DBTestCase):
|
||||||
self.assertEqual(node.connection_port.get('token'), 'fake-token')
|
self.assertEqual(node.connection_port.get('token'), 'fake-token')
|
||||||
self.assertEqual(node.attributes,
|
self.assertEqual(node.attributes,
|
||||||
{'key1': 'value1', 'key2': 'value2'})
|
{'key1': 'value1', 'key2': 'value2'})
|
||||||
|
self.assertEqual(node.cloud, 'admin-cluster.local')
|
||||||
|
self.assertEqual(node.host_id, 'k8s-default-pool-abcd-1234')
|
||||||
|
|
||||||
node.state = zk.DELETING
|
node.state = zk.DELETING
|
||||||
self.zk.storeNode(node)
|
self.zk.storeNode(node)
|
||||||
|
@ -150,6 +155,8 @@ class TestDriverKubernetes(tests.DBTestCase):
|
||||||
self.assertIsNotNone(node.launcher)
|
self.assertIsNotNone(node.launcher)
|
||||||
self.assertEqual(node.connection_type, 'namespace')
|
self.assertEqual(node.connection_type, 'namespace')
|
||||||
self.assertEqual(node.connection_port.get('token'), 'fake-token')
|
self.assertEqual(node.connection_port.get('token'), 'fake-token')
|
||||||
|
self.assertEqual(node.cloud, 'admin-cluster.local')
|
||||||
|
self.assertIsNone(node.host_id)
|
||||||
|
|
||||||
node.state = zk.DELETING
|
node.state = zk.DELETING
|
||||||
self.zk.storeNode(node)
|
self.zk.storeNode(node)
|
||||||
|
|
|
@ -114,6 +114,9 @@ class FakeCoreClient(object):
|
||||||
class FakePod:
|
class FakePod:
|
||||||
class status:
|
class status:
|
||||||
phase = "Running"
|
phase = "Running"
|
||||||
|
|
||||||
|
class spec:
|
||||||
|
node_name = "k8s-default-pool-abcd-1234"
|
||||||
return FakePod
|
return FakePod
|
||||||
|
|
||||||
|
|
||||||
|
@ -157,6 +160,8 @@ class TestDriverOpenshift(tests.DBTestCase):
|
||||||
self.assertEqual(node.shell_type, 'csh')
|
self.assertEqual(node.shell_type, 'csh')
|
||||||
self.assertEqual(node.attributes,
|
self.assertEqual(node.attributes,
|
||||||
{'key1': 'value1', 'key2': 'value2'})
|
{'key1': 'value1', 'key2': 'value2'})
|
||||||
|
self.assertEqual(node.cloud, 'admin-cluster.local')
|
||||||
|
self.assertIsNone(node.host_id)
|
||||||
|
|
||||||
node.state = zk.DELETING
|
node.state = zk.DELETING
|
||||||
self.zk.storeNode(node)
|
self.zk.storeNode(node)
|
||||||
|
|
|
@ -54,6 +54,9 @@ class FakeCoreClient(object):
|
||||||
class FakePod:
|
class FakePod:
|
||||||
class status:
|
class status:
|
||||||
phase = "Running"
|
phase = "Running"
|
||||||
|
|
||||||
|
class spec:
|
||||||
|
node_name = "k8s-default-pool-abcd-1234"
|
||||||
return FakePod
|
return FakePod
|
||||||
|
|
||||||
def delete_namespaced_pod(self, name, project):
|
def delete_namespaced_pod(self, name, project):
|
||||||
|
@ -104,6 +107,8 @@ class TestDriverOpenshiftPods(tests.DBTestCase):
|
||||||
self.assertIn('ca_crt', node.connection_port)
|
self.assertIn('ca_crt', node.connection_port)
|
||||||
self.assertEqual(node.attributes,
|
self.assertEqual(node.attributes,
|
||||||
{'key1': 'value1', 'key2': 'value2'})
|
{'key1': 'value1', 'key2': 'value2'})
|
||||||
|
self.assertEqual(node.cloud, 'service-account.local')
|
||||||
|
self.assertEqual(node.host_id, 'k8s-default-pool-abcd-1234')
|
||||||
|
|
||||||
node.state = zk.DELETING
|
node.state = zk.DELETING
|
||||||
self.zk.storeNode(node)
|
self.zk.storeNode(node)
|
||||||
|
|
Loading…
Reference in New Issue