Bootaction cleanup
- Clean up the docs and code around bootactions to support the baclient work - Update the Jinja2 environment in the bootaction rendering - Refactor authentication of bootaction signal API calls Change-Id: Ic64f0c7ee09a487be750188953013f1ed3cd99cb
This commit is contained in:
parent
0f39a55942
commit
9a52dca199
|
@ -112,6 +112,9 @@ object in details can be extended with additional fields as needed.
|
||||||
Once a POST containing the ``status`` field is made to a bootaction-id, that bootaction-id can no
|
Once a POST containing the ``status`` field is made to a bootaction-id, that bootaction-id can no
|
||||||
longer be updated with status changes nor additional detailed status messages.
|
longer be updated with status changes nor additional detailed status messages.
|
||||||
|
|
||||||
|
Each request made must contain the ``X-Bootaction-Key`` header with the correct hex
|
||||||
|
key for ``bootaction-id``.
|
||||||
|
|
||||||
validatedesign API
|
validatedesign API
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
@ -111,9 +111,11 @@ template
|
||||||
- node.network.[network_name].cidr - CIDR of [network_name]
|
- node.network.[network_name].cidr - CIDR of [network_name]
|
||||||
- node.network.[network_name].dns_suffix - DNS suffix of [network_name]
|
- node.network.[network_name].dns_suffix - DNS suffix of [network_name]
|
||||||
- node.hostname - Hostname of the node
|
- node.hostname - Hostname of the node
|
||||||
|
- node.domain - DNS Domain of the primary network on the node
|
||||||
- node.tags - Sequence of tags assigned to this node
|
- node.tags - Sequence of tags assigned to this node
|
||||||
- node.labels - Key, value pairs of both explicit and dynamic labels for this node
|
- node.labels - Key, value pairs of both explicit and dynamic labels for this node
|
||||||
- action.key - A key that uniquely identifies this boot action on this node. Can be used for signaling boot action result.
|
- action.action_id - A ULID that uniquely identifies this boot action on this node. Can be used for signaling boot action result.
|
||||||
|
- action.action_key - A random key in hex that authenticates API calls for signaling boot action result.
|
||||||
- action.report_url - The URL that can be POSTed to for reporting boot action result.
|
- action.report_url - The URL that can be POSTed to for reporting boot action result.
|
||||||
- action.design_ref - The design reference for the deployment that initiated the bootaction
|
- action.design_ref - The design reference for the deployment that initiated the bootaction
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,8 @@ RUN pip3 install \
|
||||||
--no-cache-dir \
|
--no-cache-dir \
|
||||||
-r /tmp/drydock/requirements-lock.txt
|
-r /tmp/drydock/requirements-lock.txt
|
||||||
|
|
||||||
|
COPY ./alembic /tmp/drydock/alembic
|
||||||
|
COPY ./alembic.ini /tmp/drydock/alembic.ini
|
||||||
COPY ./python /tmp/drydock/python
|
COPY ./python /tmp/drydock/python
|
||||||
COPY ${BUILD_DIR}/baclient /tmp/drydock/python/drydock_provisioner/assets/baclient
|
COPY ${BUILD_DIR}/baclient /tmp/drydock/python/drydock_provisioner/assets/baclient
|
||||||
|
|
||||||
|
|
|
@ -176,11 +176,13 @@ class BootactionAssetsResource(StatefulResource):
|
||||||
if hostname in ba.target_nodes:
|
if hostname in ba.target_nodes:
|
||||||
ba_status = ba_status_list.get(ba.name, None)
|
ba_status = ba_status_list.get(ba.name, None)
|
||||||
action_id = ba_status.get('action_id')
|
action_id = ba_status.get('action_id')
|
||||||
|
action_key = ba_status.get('identity_key')
|
||||||
assets.extend(
|
assets.extend(
|
||||||
ba.render_assets(
|
ba.render_assets(
|
||||||
hostname,
|
hostname,
|
||||||
site_design,
|
site_design,
|
||||||
action_id,
|
action_id,
|
||||||
|
action_key,
|
||||||
task.design_ref,
|
task.design_ref,
|
||||||
type_filter=asset_type_filter))
|
type_filter=asset_type_filter))
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ class BootAction(base.DrydockPersistentObject, base.DrydockObject):
|
||||||
nodename,
|
nodename,
|
||||||
site_design,
|
site_design,
|
||||||
action_id,
|
action_id,
|
||||||
|
action_key,
|
||||||
design_ref,
|
design_ref,
|
||||||
type_filter=None):
|
type_filter=None):
|
||||||
"""Render all of the assets in this bootaction.
|
"""Render all of the assets in this bootaction.
|
||||||
|
@ -77,6 +78,8 @@ class BootAction(base.DrydockPersistentObject, base.DrydockObject):
|
||||||
:param site_design: a objects.SiteDesign instance holding the design sets
|
:param site_design: a objects.SiteDesign instance holding the design sets
|
||||||
:param action_id: a 128-bit ULID action_id of the boot action
|
:param action_id: a 128-bit ULID action_id of the boot action
|
||||||
the assets are part of
|
the assets are part of
|
||||||
|
:param action_key: a 256-bit random key to authenticate API calls
|
||||||
|
for updating the status of this bootaction
|
||||||
:param design_ref: the design ref this boot action was initiated under
|
:param design_ref: the design ref this boot action was initiated under
|
||||||
:param type_filter: optional filter of the types of assets to render
|
:param type_filter: optional filter of the types of assets to render
|
||||||
"""
|
"""
|
||||||
|
@ -84,7 +87,7 @@ class BootAction(base.DrydockPersistentObject, base.DrydockObject):
|
||||||
for a in self.asset_list:
|
for a in self.asset_list:
|
||||||
if type_filter is None or (type_filter is not None
|
if type_filter is None or (type_filter is not None
|
||||||
and a.type == type_filter):
|
and a.type == type_filter):
|
||||||
a.render(nodename, site_design, action_id, design_ref)
|
a.render(nodename, site_design, action_id, action_key, design_ref)
|
||||||
assets.append(a)
|
assets.append(a)
|
||||||
|
|
||||||
return assets
|
return assets
|
||||||
|
@ -140,7 +143,7 @@ class BootActionAsset(base.DrydockObject):
|
||||||
super().__init__(package_list=package_list, permissions=mode, **kwargs)
|
super().__init__(package_list=package_list, permissions=mode, **kwargs)
|
||||||
self.rendered_bytes = None
|
self.rendered_bytes = None
|
||||||
|
|
||||||
def render(self, nodename, site_design, action_id, design_ref):
|
def render(self, nodename, site_design, action_id, action_key, design_ref):
|
||||||
"""Render this asset into a base64 encoded string.
|
"""Render this asset into a base64 encoded string.
|
||||||
|
|
||||||
The ``nodename`` and ``action_id`` will be used to construct
|
The ``nodename`` and ``action_id`` will be used to construct
|
||||||
|
@ -149,10 +152,11 @@ class BootActionAsset(base.DrydockObject):
|
||||||
:param nodename: the name of the node where the asset will be deployed
|
:param nodename: the name of the node where the asset will be deployed
|
||||||
:param site_design: instance of objects.SiteDesign
|
:param site_design: instance of objects.SiteDesign
|
||||||
:param action_id: a 128-bit ULID boot action id
|
:param action_id: a 128-bit ULID boot action id
|
||||||
|
:param action_key: a 256-bit random key for API auth
|
||||||
:param design_ref: The design ref this bootaction was initiated under
|
:param design_ref: The design ref this bootaction was initiated under
|
||||||
"""
|
"""
|
||||||
tpl_ctx = self._get_template_context(nodename, site_design, action_id,
|
tpl_ctx = self._get_template_context(nodename, site_design, action_id,
|
||||||
design_ref)
|
action_key, design_ref)
|
||||||
|
|
||||||
if self.location is not None:
|
if self.location is not None:
|
||||||
rendered_location = self.execute_pipeline(
|
rendered_location = self.execute_pipeline(
|
||||||
|
@ -207,27 +211,30 @@ class BootActionAsset(base.DrydockObject):
|
||||||
return package_list
|
return package_list
|
||||||
|
|
||||||
def _get_template_context(self, nodename, site_design, action_id,
|
def _get_template_context(self, nodename, site_design, action_id,
|
||||||
design_ref):
|
action_key, design_ref):
|
||||||
"""Create a context to be used for template rendering.
|
"""Create a context to be used for template rendering.
|
||||||
|
|
||||||
:param nodename: The name of the node for the bootaction
|
:param nodename: The name of the node for the bootaction
|
||||||
:param site_design: The full site design
|
:param site_design: The full site design
|
||||||
:param action_id: the ULID assigned to the boot action using this context
|
:param action_id: the ULID assigned to the boot action using this context
|
||||||
|
:param action_key: a 256 bit random key for API auth
|
||||||
:param design_ref: The design reference representing ``site_design``
|
:param design_ref: The design reference representing ``site_design``
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return dict(
|
return dict(
|
||||||
node=self._get_node_context(nodename, site_design),
|
node=self._get_node_context(nodename, site_design),
|
||||||
action=self._get_action_context(action_id, design_ref))
|
action=self._get_action_context(action_id, action_key, design_ref))
|
||||||
|
|
||||||
def _get_action_context(self, action_id, design_ref):
|
def _get_action_context(self, action_id, action_key, design_ref):
|
||||||
"""Create the action-specific context items for template rendering.
|
"""Create the action-specific context items for template rendering.
|
||||||
|
|
||||||
:param action_id: ULID of this boot action
|
:param action_id: ULID of this boot action
|
||||||
|
:param action_key: random key of this boot action
|
||||||
:param design_ref: Design reference representing the site design
|
:param design_ref: Design reference representing the site design
|
||||||
"""
|
"""
|
||||||
return dict(
|
return dict(
|
||||||
key=ulid2.ulid_to_base32(action_id),
|
action_id=ulid2.ulid_to_base32(action_id),
|
||||||
|
action_key=action_key.hex(),
|
||||||
report_url=config.config_mgr.conf.bootactions.report_url,
|
report_url=config.config_mgr.conf.bootactions.report_url,
|
||||||
design_ref=design_ref)
|
design_ref=design_ref)
|
||||||
|
|
||||||
|
|
|
@ -22,4 +22,4 @@ docker run --rm --net host postgres:9.5 psql -h localhost -c "create database dr
|
||||||
|
|
||||||
export DRYDOCK_DB_URL="postgresql+psycopg2://drydock:drydock@localhost:5432/drydock"
|
export DRYDOCK_DB_URL="postgresql+psycopg2://drydock:drydock@localhost:5432/drydock"
|
||||||
|
|
||||||
sudo docker run --rm -t --net=host -e DRYDOCK_DB_URL="$DRYDOCK_DB_URL" --entrypoint /usr/local/bin/alembic $IMAGE upgrade head
|
sudo docker run --rm -t --net=host -e DRYDOCK_DB_URL="$DRYDOCK_DB_URL" -w /tmp/drydock --entrypoint /usr/local/bin/alembic $IMAGE upgrade head
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
"""Test that boot action assets are rendered correctly."""
|
"""Test that boot action assets are rendered correctly."""
|
||||||
|
|
||||||
import ulid2
|
import ulid2
|
||||||
|
import os
|
||||||
|
|
||||||
from drydock_provisioner.statemgmt.state import DrydockState
|
from drydock_provisioner.statemgmt.state import DrydockState
|
||||||
|
|
||||||
|
@ -32,8 +33,9 @@ class TestBootactionRenderAction(object):
|
||||||
|
|
||||||
ba = design_data.get_bootaction('helloworld')
|
ba = design_data.get_bootaction('helloworld')
|
||||||
action_id = ulid2.generate_binary_ulid()
|
action_id = ulid2.generate_binary_ulid()
|
||||||
|
action_key = os.urandom(32)
|
||||||
assets = ba.render_assets('compute01', design_data, action_id,
|
assets = ba.render_assets('compute01', design_data, action_id,
|
||||||
design_ref)
|
action_key, design_ref)
|
||||||
|
|
||||||
assert 'compute01' in assets[0].rendered_bytes.decode('utf-8')
|
assert 'compute01' in assets[0].rendered_bytes.decode('utf-8')
|
||||||
|
|
||||||
|
@ -50,12 +52,34 @@ class TestBootactionRenderAction(object):
|
||||||
|
|
||||||
ba = design_data.get_bootaction('helloworld')
|
ba = design_data.get_bootaction('helloworld')
|
||||||
action_id = ulid2.generate_binary_ulid()
|
action_id = ulid2.generate_binary_ulid()
|
||||||
|
action_key = os.urandom(32)
|
||||||
assets = ba.render_assets('compute01', design_data, action_id,
|
assets = ba.render_assets('compute01', design_data, action_id,
|
||||||
design_ref)
|
action_key, design_ref)
|
||||||
|
|
||||||
assert 'deckhand_fullsite.yaml' in assets[2].rendered_bytes.decode(
|
assert 'deckhand_fullsite.yaml' in assets[2].rendered_bytes.decode(
|
||||||
'utf-8')
|
'utf-8')
|
||||||
|
|
||||||
|
def test_bootaction_render_key(self, input_files, deckhand_ingester,
|
||||||
|
setup):
|
||||||
|
"""Test that a bootaction can render the correct action_id and
|
||||||
|
action_key needed by the signalling API."""
|
||||||
|
input_file = input_files.join("deckhand_fullsite.yaml")
|
||||||
|
|
||||||
|
design_state = DrydockState()
|
||||||
|
design_ref = "file://%s" % str(input_file)
|
||||||
|
|
||||||
|
design_status, design_data = deckhand_ingester.ingest_data(
|
||||||
|
design_state=design_state, design_ref=design_ref)
|
||||||
|
|
||||||
|
ba = design_data.get_bootaction('helloworld')
|
||||||
|
action_id = ulid2.generate_binary_ulid()
|
||||||
|
action_key = os.urandom(32)
|
||||||
|
assets = ba.render_assets('compute01', design_data, action_id,
|
||||||
|
action_key, design_ref)
|
||||||
|
|
||||||
|
assert action_key.hex() in assets[2].rendered_bytes.decode('utf-8')
|
||||||
|
assert ulid2.ulid_to_base32(action_id) in assets[2].rendered_bytes.decode('utf-8')
|
||||||
|
|
||||||
def test_bootaction_network_context(self, input_files,
|
def test_bootaction_network_context(self, input_files,
|
||||||
deckhand_orchestrator, setup):
|
deckhand_orchestrator, setup):
|
||||||
"""Test that a boot action creates proper network context."""
|
"""Test that a boot action creates proper network context."""
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
import ulid2
|
import ulid2
|
||||||
import tarfile
|
import tarfile
|
||||||
import io
|
import io
|
||||||
|
import os
|
||||||
|
|
||||||
import drydock_provisioner.objects as objects
|
import drydock_provisioner.objects as objects
|
||||||
from drydock_provisioner.statemgmt.state import DrydockState
|
from drydock_provisioner.statemgmt.state import DrydockState
|
||||||
|
@ -39,8 +40,9 @@ class TestClass(object):
|
||||||
|
|
||||||
ba = design_data.get_bootaction('helloworld')
|
ba = design_data.get_bootaction('helloworld')
|
||||||
action_id = ulid2.generate_binary_ulid()
|
action_id = ulid2.generate_binary_ulid()
|
||||||
|
action_key = os.urandom(32)
|
||||||
assets = ba.render_assets(target_host, design_data, action_id,
|
assets = ba.render_assets(target_host, design_data, action_id,
|
||||||
design_ref)
|
action_key, design_ref)
|
||||||
|
|
||||||
assert len(assets) > 0
|
assert len(assets) > 0
|
||||||
|
|
||||||
|
|
|
@ -541,9 +541,11 @@ data:
|
||||||
- path: /var/tmp/designref.sh
|
- path: /var/tmp/designref.sh
|
||||||
type: file
|
type: file
|
||||||
permissions: '500'
|
permissions: '500'
|
||||||
data: e3sgYWN0aW9uLmRlc2lnbl9yZWYgfX0K
|
data: |
|
||||||
|
{{ action.design_ref }}
|
||||||
|
{{ action.action_id }}
|
||||||
|
{{ action.action_key }}
|
||||||
data_pipeline:
|
data_pipeline:
|
||||||
- base64_decode
|
|
||||||
- utf8_decode
|
- utf8_decode
|
||||||
- template
|
- template
|
||||||
---
|
---
|
||||||
|
|
Loading…
Reference in New Issue