Add Azure gallery image support

The shared and community gallery images are another way to specify
what image to use when creating a VM.  Shared galleries are intended
for use within an organization, and community galleries are public.

This adds support for using these images.  It requires an API version
bump since the virtual machine attributes to specify them are new.

Change-Id: Ia981fcbeea6680a9d14ee8e4ec401bf227a7cc12
This commit is contained in:
James E. Blair 2023-04-21 13:30:48 -07:00
parent dfb498e797
commit 4279b4766d
8 changed files with 237 additions and 6 deletions

View File

@ -318,6 +318,8 @@ section of the configuration.
:type: dict
Specifies a private image to use via filters. Either this field,
:attr:`providers.[azure].cloud-images.shared-gallery-image`,
:attr:`providers.[azure].cloud-images.community-gallery-image`,
:attr:`providers.[azure].cloud-images.image-reference`, or
:attr:`providers.[azure].cloud-images.image-id` must be
provided.
@ -363,14 +365,72 @@ section of the configuration.
:type: str
Specifies a private image to use by ID. Either this field,
:attr:`providers.[azure].cloud-images.shared-gallery-image`,
:attr:`providers.[azure].cloud-images.community-gallery-image`,
:attr:`providers.[azure].cloud-images.image-reference`, or
:attr:`providers.[azure].cloud-images.image-filter` must be
provided.
.. attr:: shared-gallery-image
:type: dict
Specifies a shared gallery image to use by ID. Either this field,
:attr:`providers.[azure].cloud-images.community-gallery-image`,
:attr:`providers.[azure].cloud-images.image-reference`,
:attr:`providers.[azure].cloud-images.image-id`, or
:attr:`providers.[azure].cloud-images.image-filter` must be
provided.
.. attr:: gallery-name
:type: str
:required:
The name of the image gallery.
.. attr:: name
:type: str
:required:
The name of the image.
.. attr:: version
:type: str
The image version. Omit to use the latest version.
.. attr:: community-gallery-image
:type: dict
Specifies a community gallery image to use by ID. Either this field,
:attr:`providers.[azure].cloud-images.shared-gallery-image`,
:attr:`providers.[azure].cloud-images.image-reference`,
:attr:`providers.[azure].cloud-images.image-id`, or
:attr:`providers.[azure].cloud-images.image-filter` must be
provided.
.. attr:: gallery-name
:type: str
:required:
The name of the image gallery.
.. attr:: name
:type: str
:required:
The name of the image.
.. attr:: version
:type: str
The image version. Omit to use the latest version.
.. attr:: image-reference
:type: dict
Specifies a public image to use. Either this field,
:attr:`providers.[azure].cloud-images.shared-gallery-image`,
:attr:`providers.[azure].cloud-images.community-gallery-image`,
:attr:`providers.[azure].cloud-images.image-id`, or
:attr:`providers.[azure].cloud-images.image-filter` must be
provided.

View File

@ -681,7 +681,7 @@ class AzureAdapter(statemachine.Adapter):
remote_image = self._getImage(image_external_id)
image_reference = {'id': remote_image['id']}
elif image_reference:
# This is a cloud image with aser supplied image-filter;
# This is a cloud image with user supplied image-filter;
# we already found the reference.
image = label.cloud_image
else:
@ -690,6 +690,28 @@ class AzureAdapter(statemachine.Adapter):
image = label.cloud_image
if label.cloud_image.image_reference:
image_reference = label.cloud_image.image_reference
elif label.cloud_image.community_gallery_image:
g = label.cloud_image.community_gallery_image
gallery_image_id = (
f"/CommunityGalleries/{g['gallery-name']}"
f"/Images/{g['name']}"
)
if g.get('version'):
gallery_image_id += f"/Versions/{g['version']}"
image_reference = {
'communityGalleryImageId': gallery_image_id
}
elif label.cloud_image.shared_gallery_image:
g = label.cloud_image.shared_gallery_image
gallery_image_id = (
f"/SharedGalleries/{g['gallery-name']}"
f"/Images/{g['name']}"
)
if g.get('version'):
gallery_image_id += f"/Versions/{g['version']}"
image_reference = {
'sharedGalleryImageId': gallery_image_id
}
else:
image_reference = {'id': label.cloud_image.image_id}
os_profile = {'computerName': hostname}

View File

@ -240,7 +240,7 @@ class AzureCloud:
self,
providerId='Microsoft.Compute',
resource='virtualMachines',
apiVersion='2020-12-01')
apiVersion='2022-11-01')
self.disks = AzureResourceProviderCRUD(
self,
providerId='Microsoft.Compute',

View File

@ -39,6 +39,10 @@ class AzureProviderCloudImage(ConfigValue):
self.image_reference = image.get('image-reference')
self.image_filter = image.get('image-filter')
self.image_id = image.get('image-id')
self.shared_gallery_image = image.get(
'shared-gallery-image')
self.community_gallery_image = image.get(
'community-gallery-image')
self.python_path = image.get('python-path', 'auto')
self.shell_type = image.get('shell-type')
self.connection_type = image.get('connection-type', 'ssh')
@ -67,6 +71,12 @@ class AzureProviderCloudImage(ConfigValue):
'tags': dict,
}
azure_gallery_image = {
v.Required('gallery-name'): str,
v.Required('name'): str,
'version': str,
}
return v.All({
v.Required('name'): str,
v.Required('username'): str,
@ -77,15 +87,24 @@ class AzureProviderCloudImage(ConfigValue):
v.Exclusive('image-reference', 'spec'): azure_image_reference,
v.Exclusive('image-id', 'spec'): str,
v.Exclusive('image-filter', 'spec'): azure_image_filter,
v.Exclusive('community-gallery-image', 'spec'):
azure_gallery_image,
v.Exclusive('shared-gallery-image', 'spec'):
azure_gallery_image,
'connection-type': str,
'connection-port': int,
'python-path': str,
'shell-type': str,
}, {
v.Required(
v.Any('image-reference', 'image-id', 'image-filter'),
msg=('Provide either "image-reference", '
'"image-filter", or "image-id" keys')
v.Any('image-reference', 'image-id', 'image-filter',
'community-gallery-image',
'shared-gallery-image',
),
msg=('Provide one of "image-reference", '
'"image-filter", "image-id", '
'"community-gallery-image", or '
'"shared-gallery-image" keys')
): object,
object: object,
})

View File

@ -0,0 +1,59 @@
webapp:
port: 8005
listen_address: '0.0.0.0'
zookeeper-servers:
- host: {zookeeper_host}
port: {zookeeper_port}
chroot: {zookeeper_chroot}
zookeeper-tls:
ca: {zookeeper_ca}
cert: {zookeeper_cert}
key: {zookeeper_key}
labels:
- name: community-bionic
min-ready: 0
- name: shared-bionic
min-ready: 0
providers:
- name: azure
driver: azure
zuul-public-key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+mplenM+m6pNY9Un3fpO9eqf808Jrfb3d1gXg7BZVawCvtEZ/cDYvLQ3OF1AeL2kcIC0UAIglM5JXae7yO5CJbJRdkbXvv0u1LvpLxYSPM4ATR0r4IseC5YVxkfJQNi4ixSwTqD4ScEkuCXcSqSU9M+hB+KlnwXoR4IcYHf7vD2Z0Mdwm2ikk3SeERmspmMxx/uz0SPn58QxONuoTlNWQKqDWsV6bRyoPa6HWccMrIH1/e7E69Nw/30oioOQpKBgaDCauh+QkDtSkjRpRMOV47ZFh16Q9DqMgLx+FD8z6++9rsHlB65Zas1xyQsiRCFG09s00b7OR7Xz9ukQ5+vXV
resource-group-location: centralus
location: centralus
resource-group: nodepool
auth-path: {auth_path}
subnet-id: /subscriptions/c35cf7df-ed75-4c85-be00-535409a85120/resourceGroups/nodepool/providers/Microsoft.Network/virtualNetworks/NodePool/subnets/default
cloud-images:
- name: community-bionic
username: zuul
shell-type: sh
community-gallery-image:
gallery-name: community-gallery
name: community-image
version: latest
- name: shared-bionic
username: zuul
shell-type: sh
shared-gallery-image:
gallery-name: shared-gallery
name: shared-image
version: latest
pools:
- name: main
max-servers: 10
node-attributes:
key1: value1
key2: value2
labels:
- name: community-bionic
cloud-image: community-bionic
hardware-profile:
vm-size: Standard_B1ls
- name: shared-bionic
cloud-image: shared-bionic
hardware-profile:
vm-size: Standard_B1ls

View File

@ -325,7 +325,7 @@ class FakeAzureFixture(fixtures.Fixture):
self._setup_crud(ResourceGroupsCRUD, '2020-06-01',
resource_grouped=False)
self._setup_crud(VirtualMachinesCRUD, '2020-12-01')
self._setup_crud(VirtualMachinesCRUD, '2022-11-01')
self._setup_crud(NetworkInterfacesCRUD, '2020-07-01')
self._setup_crud(PublicIPAddressesCRUD, '2020-07-01')
self._setup_crud(DisksCRUD, '2020-06-30')

View File

@ -213,6 +213,72 @@ class TestDriverAzure(tests.DBTestCase):
"/resourceGroups/nodepool/providers/Microsoft.Compute"
"/images/test-image-1234")
def test_azure_community_gallery_image(self):
configfile = self.setup_config(
'azure-gallery-image.yaml',
auth_path=self.fake_azure.auth_file.name)
pool = self.useNodepool(configfile, watermark_sleep=1)
self.startPool(pool)
req = zk.NodeRequest()
req.state = zk.REQUESTED
req.node_types.append('community-bionic')
self.zk.storeNodeRequest(req)
req = self.waitForNodeRequest(req)
self.assertEqual(req.state, zk.FULFILLED)
self.assertNotEqual(req.nodes, [])
node = self.zk.getNode(req.nodes[0])
self.assertEqual(node.allocated_to, req.id)
self.assertEqual(node.state, zk.READY)
self.assertIsNotNone(node.launcher)
self.assertEqual(node.connection_type, 'ssh')
self.assertEqual(node.shell_type, 'sh')
self.assertEqual(node.attributes,
{'key1': 'value1', 'key2': 'value2'})
self.assertEqual(node.host_keys, ['ssh-rsa FAKEKEY'])
self.assertEqual(
self.fake_azure.crud['Microsoft.Compute/virtualMachines'].
requests[0]['properties']['storageProfile']
['imageReference']['communityGalleryImageId'],
"/CommunityGalleries/community-gallery"
"/Images/community-image"
"/Versions/latest")
def test_azure_shared_gallery_image(self):
configfile = self.setup_config(
'azure-gallery-image.yaml',
auth_path=self.fake_azure.auth_file.name)
pool = self.useNodepool(configfile, watermark_sleep=1)
self.startPool(pool)
req = zk.NodeRequest()
req.state = zk.REQUESTED
req.node_types.append('shared-bionic')
self.zk.storeNodeRequest(req)
req = self.waitForNodeRequest(req)
self.assertEqual(req.state, zk.FULFILLED)
self.assertNotEqual(req.nodes, [])
node = self.zk.getNode(req.nodes[0])
self.assertEqual(node.allocated_to, req.id)
self.assertEqual(node.state, zk.READY)
self.assertIsNotNone(node.launcher)
self.assertEqual(node.connection_type, 'ssh')
self.assertEqual(node.shell_type, 'sh')
self.assertEqual(node.attributes,
{'key1': 'value1', 'key2': 'value2'})
self.assertEqual(node.host_keys, ['ssh-rsa FAKEKEY'])
self.assertEqual(
self.fake_azure.crud['Microsoft.Compute/virtualMachines'].
requests[0]['properties']['storageProfile']
['imageReference']['sharedGalleryImageId'],
"/SharedGalleries/shared-gallery"
"/Images/shared-image"
"/Versions/latest")
def test_azure_image_filter_name(self):
self.fake_azure.crud['Microsoft.Compute/images'].items.append(
make_image('test1', {'foo': 'bar'}))

View File

@ -0,0 +1,5 @@
---
features:
- |
The Azure driver now support specifying community and shared
gallery images.