Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/bugfix/GH-2569-add-digest-for-de…
Browse files Browse the repository at this point in the history
…x-config' into w/2.6/bugfix/GH-2569-add-digest-for-dex-config
  • Loading branch information
TeddyAndrieux committed May 26, 2020
2 parents 081b420 + dbb25c4 commit c3bc1d0
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 18 deletions.
4 changes: 4 additions & 0 deletions charts/dex.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ extraVolumeMounts:
- name: dex-login
mountPath: /web/themes/scality

podAnnotations:
# Override default checksum as we want to manage it with salt
checksum/config: '__slot__:salt:metalk8s_kubernetes.get_object_digest(kind="Secret", apiVersion="v1", namespace="metalk8s-auth", name="dex", object_key="data:config.yaml")'

certs:
web:
create: false
Expand Down
14 changes: 0 additions & 14 deletions docs/operation/cluster_and_service_configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,6 @@ To add a new static user, perform the following operations:
salt-master-bootstrap -- salt-run \\
state.sls metalk8s.addons.dex.deployed saltenv=metalk8s-|version|
#. From the Bootstrap node, restart the Dex deployments.

.. code-block:: shell
root@bootstrap $ kubectl --kubeconfig /etc/kubernetes/admin.conf \
rollout restart deployment dex -n metalk8s-auth
#. Finally, create and apply the required :file:`ClusterRoleBinding.yaml` file
that ensures that the newly added static user is bound to a Cluster Role.

Expand Down Expand Up @@ -266,13 +259,6 @@ To change the password of an existing user, perform the following operations:
salt-master-bootstrap -- salt-run \\
state.sls metalk8s.addons.dex.deployed saltenv=metalk8s-|version|
#. From the Bootstrap node, restart the Dex deployments.

.. code-block:: shell
root@bootstrap $ kubectl --kubeconfig /etc/kubernetes/admin.conf \
rollout restart deployment dex -n metalk8s-auth
#. Verify that the password has been changed and you can log in to the MetalK8s
UI using the new password

Expand Down
38 changes: 38 additions & 0 deletions salt/_modules/metalk8s.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from salt.pillar import get_pillar
from salt.exceptions import CommandExecutionError
import salt.utils.args
import salt.utils.files

log = logging.getLogger(__name__)
Expand Down Expand Up @@ -287,3 +288,40 @@ def check_pillar_keys(keys, refresh=True, pillar=None, raise_error=True):
return False

return True


def format_slots(data):
"""Helper to replace slots in nested dictionnary
"__slots__:salt:module.function(arg1, arg2, kwarg1=abc, kwargs2=cde)
Arguments:
data: Data structure to format
"""
slots_callers = {
"salt": __salt__
}

if isinstance(data, list):
return [format_slots(elt) for elt in data]

if isinstance(data, dict):
return {key: format_slots(value) for key, value in data.items()}

if isinstance(data, basestring) and data.startswith('__slot__:'):
fmt = data.split(":", 2)
if len(fmt) != 3:
log.warning("Malformed slot: %s", data)
return data
if fmt[1] not in slots_callers:
log.warning(
"Malformed slot, only %s supported: %s",
slots_callers.keys(), data
)
return data

fun, args, kwargs = salt.utils.args.parse_function(fmt[2])

return slots_callers[fmt[1]][fun](*args, **kwargs)

return data
37 changes: 37 additions & 0 deletions salt/_modules/metalk8s_kubernetes.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ def method(manifest=None, name=None, kind=None, apiVersion=None,
)
)

# Format slots on the manifest
manifest = __salt__.metalk8s.format_slots(manifest)

# Adding label containing metalk8s version (retrieved from saltenv)
if action in ['create', 'replace']:
match = re.search(r'^metalk8s-(?P<version>.+)$', saltenv)
Expand Down Expand Up @@ -351,3 +354,37 @@ def list_objects(kind, apiVersion, namespace='default', all_namespaces=False,
raise CommandExecutionError('{}: {!s}'.format(base_msg, exc))

return [obj.to_dict() for obj in result.items]


def get_object_digest(object_key=None, checksum='sha256', *args, **kwargs):
"""
Helper to get the digest of one kubernetes object or from a specific key
of this object (usefull to get the digest of one config from ConfigMap)
CLI Examples:
.. code-block:: bash
salt-call metalk8s_kubernetes.get_object_digest kind="ConfigMap" apiVersion="v1" name="my-config-map" object_key="config.yaml"
salt-call metalk8s_kubernetes.get_object_digest kind="Pod" apiVersion="v1" name="my-pod"
"""
obj = get_object(*args, **kwargs)

if not obj:
raise CommandExecutionError('Unable to find the object')

if object_key:
if not isinstance(object_key, list):
object_key = object_key.split(':')

for key in object_key:
try:
obj = obj[key]
except KeyError:
raise CommandExecutionError(
'Unable to find key "{}" in the object'.format(
'.'.join(object_key)
)
)

return __salt__.hashutil.digest(str(obj), checksum=checksum)
3 changes: 2 additions & 1 deletion salt/metalk8s/addons/dex/deployed/chart.sls
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ spec:
template:
metadata:
annotations:
checksum/config: d58a2489f8f7fd4df3f78cad5ea6ac51e7eda9ca076c41689ce853539ff2a15b
checksum/config: __slot__:salt:metalk8s_kubernetes.get_object_digest(kind="Secret",
apiVersion="v1", namespace="metalk8s-auth", name="dex", object_key="data:config.yaml")
labels:
app.kubernetes.io/component: dex
app.kubernetes.io/instance: dex
Expand Down
11 changes: 11 additions & 0 deletions tests/post/features/service_configuration.feature
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ Feature: Cluster and Services Configurations
When we update the CSC 'spec.deployment.replicas' to '3'
Then we have '3' at 'status.available_replicas' for 'dex' Deployment in namespace 'metalk8s-auth'

Scenario: Update Admin static user password
Given: the Kubernetes API is available
And we have a 'metalk8s-dex-config' CSC in namespace 'metalk8s-auth'
# NOTE: Consider that admin user is the first of the userlist
# Update password to "new-password"
When we update the CSC 'spec.localuserstore.userlist.0.hash' to '$2y$14$pDe0vj917rR3XJQ5iEZvhuSGoWkZg2/qBN/mMLqwFSz9S7EYcbIpO'
Then the control-plane Ingress path '/oidc' is available
And pods with label 'app.kubernetes.io/name=dex' are 'Ready'
And we are not able to login to Dex as '[email protected]' using password 'password'
And we are able to login to Dex as '[email protected]' using password 'new-password'

Scenario: Customization of pre-defined Prometheus rules
Given the Kubernetes API is available
And pods with label 'app=prometheus' are 'Ready'
Expand Down
36 changes: 36 additions & 0 deletions tests/post/steps/test_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,42 @@ def successful_login(host, context, status_code):
assert auth_response.headers.get('location') is not None


@then(parsers.parse(
"we are able to login to Dex as '{username}' using password '{password}'"))
def dex_login_success(
host,
control_plane_ip,
username,
password,
context,
request_retry_session
):
dex_login(
host, control_plane_ip,
username, password,
context, request_retry_session
)
successful_login(host, context, '303')


@then(parsers.parse(
"we are not able to login to Dex as '{username}' using password "
"'{password}'"))
def dex_login_fail(
host,
control_plane_ip,
username,
password,
context,
request_retry_session
):
dex_login(
host, control_plane_ip,
username, password,
context, request_retry_session
)
failed_login(host, context)

# }}}


Expand Down
6 changes: 6 additions & 0 deletions tests/post/steps/test_service_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ def test_service_config_propagation(host):
pass


@scenario('../features/service_configuration.feature',
'Update Admin static user password')
def test_static_user_change(host):
pass


@scenario('../features/service_configuration.feature',
'Customization of pre-defined Prometheus rules')
def test_prometheus_rules_customization(host):
Expand Down
13 changes: 10 additions & 3 deletions tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,11 @@ def get_dict_element(data, path, delimiter='.'):
Traverse a dict using a 'delimiter' on a target string.
getitem(a, b) returns the value of a at index b
"""
return functools.reduce(operator.getitem, path.split(delimiter), data)
return functools.reduce(
operator.getitem,
(int(k) if k.isdigit() else k for k in path.split(delimiter)),
data
)


def set_dict_element(data, path, value, delimiter='.'):
Expand All @@ -176,9 +180,12 @@ def set_dict_element(data, path, value, delimiter='.'):
and replace the value of a key
"""
current = data
elements = path.split(delimiter)
elements = [int(k) if k.isdigit() else k for k in path.split(delimiter)]
for element in elements[:-1]:
current = current.setdefault(element, {})
if isinstance(element, int):
current = current[element] if len(current) > element else []
else:
current = current.setdefault(element, {})
current[elements[-1]] = value


Expand Down

0 comments on commit c3bc1d0

Please sign in to comment.