Skip to content

Commit

Permalink
Deploy resources from EjsonSecretProvisioner
Browse files Browse the repository at this point in the history
  • Loading branch information
DazWorrall committed Feb 26, 2019
1 parent f4cf77b commit 57d3e9a
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 35 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## next

*Features*
- Support for deploying Secrets from templates ([#424](https://github.com/Shopify/kubernetes-deploy/pull/424)).

*Bug fixes*
- Attempting to deploy from a directory that only contains `secrets.ejson` will no longer fail deploy ([#416](https://github.com/Shopify/kubernetes-deploy/pull/416))

Expand Down
17 changes: 9 additions & 8 deletions lib/kubernetes-deploy/deploy_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ def prune_whitelist
core/v1/Pod
core/v1/Service
core/v1/ResourceQuota
core/v1/Secret
batch/v1/Job
extensions/v1beta1/DaemonSet
extensions/v1beta1/Deployment
Expand Down Expand Up @@ -136,7 +137,6 @@ def run!(verify_result: true, allow_protected_ns: false, prune: true)

@logger.phase_heading("Checking initial resource statuses")
check_initial_status(resources)
create_ejson_secrets(prune)

if deploy_has_priority_resources?(resources)
@logger.phase_heading("Predeploying priority resources")
Expand Down Expand Up @@ -242,20 +242,21 @@ def check_initial_status(resources)
end
measure_method(:check_initial_status, "initial_status.duration")

def create_ejson_secrets(prune)
def secrets_from_ejson
ejson = EjsonSecretProvisioner.new(
namespace: @namespace,
context: @context,
template_dir: @template_dir,
logger: @logger,
prune: prune,
)
return unless ejson.secret_changes_required?

@logger.phase_heading("Deploying kubernetes secrets from #{EjsonSecretProvisioner::EJSON_SECRETS_FILE}")
ejson.run
unless ejson.resources.empty?
@logger.info(
"Generated #{ejson.resources.size} kubernetes secrets from #{EjsonSecretProvisioner::EJSON_SECRETS_FILE}"
)
end
ejson.resources
end
measure_method(:create_ejson_secrets)

def discover_resources
resources = []
Expand All @@ -275,7 +276,7 @@ def discover_resources
@logger.warn("Detected non-namespaced #{'resource'.pluralize(global.count)} which will never be pruned:")
global.each { |r| @logger.warn(" - #{r.id}") }
end
resources
resources += secrets_from_ejson
end
measure_method(:discover_resources)

Expand Down
4 changes: 2 additions & 2 deletions lib/kubernetes-deploy/kubernetes_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def build(namespace:, context:, definition:, logger:, statsd_tags:, crd: nil)
if definition["kind"].blank?
raise InvalidTemplateError.new("Template missing 'Kind'", content: definition.to_yaml)
end
if klass = class_for_kind(definition["kind"])
if (klass = class_for_kind(definition["kind"]))
return klass.new(**opts)
end
if crd
Expand All @@ -52,7 +52,7 @@ def build(namespace:, context:, definition:, logger:, statsd_tags:, crd: nil)

def class_for_kind(kind)
if KubernetesDeploy.const_defined?(kind)
return KubernetesDeploy.const_get(kind)
KubernetesDeploy.const_get(kind) # rubocop:disable Sorbet/ConstantsFromStrings
end
rescue NameError
nil
Expand Down
21 changes: 3 additions & 18 deletions test/integration-serial/serial_deploy_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,14 @@ def test_create_and_update_secrets_from_ejson
assert_deploy_success(deploy_fixtures("ejson-cloud"))
ejson_cloud.assert_all_up
assert_logs_match_all([
/Creating secret catphotoscom/,
/Creating secret unused-secret/,
/Creating secret monitoring-token/,
%r{Secret\/catphotoscom\s+Available},
%r{Secret\/unused-secret\s+Available},
%r{Secret\/monitoring-token\s+Available},
])

refute_logs_match(ejson_cloud.test_private_key)
refute_logs_match(ejson_cloud.test_public_key)
refute_logs_match(Base64.strict_encode64(ejson_cloud.catphotoscom_key_value))

# Update secrets
result = deploy_fixtures("ejson-cloud") do |fixtures|
fixtures["secrets.ejson"]["kubernetes_secrets"]["unused-secret"]["data"] = { "_test" => "a" }
end
assert_deploy_success(result)
ejson_cloud.assert_secret_present('unused-secret', { "test" => "a" }, managed: true)
ejson_cloud.assert_web_resources_up
assert_logs_match(/Updating secret unused-secret/)

refute_logs_match(ejson_cloud.test_private_key)
refute_logs_match(ejson_cloud.test_public_key)
refute_logs_match(Base64.strict_encode64(ejson_cloud.catphotoscom_key_value))
end

# This can be run in parallel when we switch to --kubeconfig (https://github.com/Shopify/kubernetes-deploy/issues/52)
Expand Down Expand Up @@ -195,7 +182,6 @@ def test_stage_related_metrics_include_custom_tags_from_namespace
KubernetesDeploy.discover_resources.duration
KubernetesDeploy.validate_resources.duration
KubernetesDeploy.initial_status.duration
KubernetesDeploy.create_ejson_secrets.duration
KubernetesDeploy.priority_resources.duration
KubernetesDeploy.apply_all.duration
KubernetesDeploy.normal_resources.duration
Expand All @@ -220,7 +206,6 @@ def test_all_expected_statsd_metrics_emitted_with_essential_tags
KubernetesDeploy.discover_resources.duration
KubernetesDeploy.validate_resources.duration
KubernetesDeploy.initial_status.duration
KubernetesDeploy.create_ejson_secrets.duration
KubernetesDeploy.priority_resources.duration
KubernetesDeploy.apply_all.duration
KubernetesDeploy.normal_resources.duration
Expand Down
29 changes: 22 additions & 7 deletions test/integration/kubernetes_deploy_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,9 @@ def test_pruning_works
prune_matcher("statefulset", "apps", "stateful-busybox"),
prune_matcher("job", "batch", "hello-job"),
prune_matcher("poddisruptionbudget", "policy", "test"),
prune_matcher("secret", "", "hello-secret"),
] # not necessarily listed in this order
expected_msgs = [/Pruned 10 resources and successfully deployed 6 resources/]
expected_msgs = [/Pruned 11 resources and successfully deployed 6 resources/]
expected_pruned.map do |resource|
expected_msgs << /The following resources were pruned:.*#{resource}/
end
Expand Down Expand Up @@ -340,6 +341,16 @@ def test_output_of_failed_unmanaged_pod
], in_order: true)
end

def test_deployment_includes_ejson_secrets
ejson_cloud = FixtureSetAssertions::EjsonCloud.new(@namespace)
ejson_cloud.create_ejson_keys_secret
assert_deploy_success(deploy_fixtures("ejson-cloud"))
ejson_cloud.assert_secret_present('unused-secret', managed: true)
assert_logs_match_all([
%r{Secret\/catphotoscom\s+Available},
], in_order: true)
end

def test_deployment_container_mounting_secret_that_does_not_exist_as_env_var_fails_quickly
result = deploy_fixtures("ejson-cloud", subset: ["web.yaml"]) do |fixtures| # exclude secret ejson
# Remove the volumes. Right now Kubernetes does not expose a useful status when mounting fails. :(
Expand Down Expand Up @@ -534,7 +545,7 @@ def test_pruning_of_secrets_created_from_ejson
fixtures["secrets.ejson"]["kubernetes_secrets"].delete("unused-secret")
end
assert_deploy_success(result)
assert_logs_match(/Pruning secret unused-secret/)
assert_logs_match(%r{The following resources were pruned:.*secret( "|\/)unused-secret})

# The removed secret was pruned
ejson_cloud.refute_resource_exists('secret', 'unused-secret')
Expand All @@ -557,24 +568,28 @@ def test_pruning_of_existing_managed_secrets_when_ejson_file_has_been_deleted
assert_deploy_success(result)

assert_logs_match_all([
"Pruning secret unused-secret",
"Pruning secret catphotoscom",
"Pruning secret monitoring-token",
%r{The following resources were pruned:.*secret( "|\/)catphotoscom},
%r{The following resources were pruned:.*secret( "|\/)monitoring-token},
%r{The following resources were pruned:.*secret( "|\/)unused-secret},
])

ejson_cloud.refute_resource_exists('secret', 'unused-secret')
ejson_cloud.refute_resource_exists('secret', 'catphotoscom')
ejson_cloud.refute_resource_exists('secret', 'monitoring-token')

# Check ejson-keys is not deleted
ejson_cloud.assert_secret_present('ejson-keys')
end

def test_can_deploy_template_dir_with_only_secrets_ejson
ejson_cloud = FixtureSetAssertions::EjsonCloud.new(@namespace)
ejson_cloud.create_ejson_keys_secret
assert_deploy_success(deploy_fixtures("ejson-cloud", subset: ["secrets.ejson"]))
assert_logs_match_all([
"Deploying kubernetes secrets from secrets.ejson",
"Result: SUCCESS",
%r{Created/updated \d+ secrets},
%r{Secret\/catphotoscom\s+Available},
%r{Secret\/unused-secret\s+Available},
%r{Secret\/monitoring-token\s+Available},
], in_order: true)
end

Expand Down

0 comments on commit 57d3e9a

Please sign in to comment.