Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use kubectl in EjsonSecretProvisioner #91

Merged
merged 2 commits into from
May 9, 2017
Merged

Use kubectl in EjsonSecretProvisioner #91

merged 2 commits into from
May 9, 2017

Conversation

KnVerey
Copy link
Contributor

@KnVerey KnVerey commented May 8, 2017

tl;dr kubeclient isn't working for some of our production clusters, so this switches EjsonSecretProvisioner over to kubectl--which is what the rest of the deploy process uses--for the time being.


When I rolled out #81 in shipit, I discovered that kubeclient does not seem to be working with our GCP clusters. It is failing with an SSL error on client.discover (see this deploy). This may be a further piece to the work @xldenis already did in #88; he is investigating.

The most meaningful change is that we need to write a tempfile to use kubectl apply for secret creation/update. Note that although the unit tests required surgery, the integration tests all passed as-is.

Why not wait for the kubeclient fix?
The current consensus is still that we want to use a gem rather than kubectl for everything we can (which doesn't include "apply" operations) in the long run, but I didn't realize that none of the tasks that already use kubeclient had been tested in our production Shipit environment. This feature is high-priority, and switching to kubeclient is far from it. With the problems we've had, we may even want to reconsider this particular gem choice.

cc @Shopify/cloudplatform

@KnVerey KnVerey requested review from camilo, kirs and mkobetic May 8, 2017 23:58
msg = secret_exists?(secret_name) ? "Updating secret #{secret_name}" : "Creating secret #{secret_name}"
KubernetesDeploy.logger.info(msg)

file = Tempfile.new(secret_name)
Copy link
Contributor Author

@KnVerey KnVerey May 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, we could use create and construct a really long command with --from-literal=k=v --from-literal=k=v .... I'm not sure if/how that works with updates though.


file = Tempfile.new(secret_name)
file.write(secret_yaml)
file.close
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe do this close on an ensure block ? otherwise you might end up on the situation where the GC takes the file away from you

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To address both this and @mkobetic comment below, kubectl won't be able to read the file unless we close it. Tempfiles are automatically GC'd when the process exits, if not sooner. Tempfile.open { |f| ... } doesn't return the file. I don't think it would be possible for the file to get GC'd when we need it in this case, since we only need it for the duration of this method, which retrains a reference to it. However, I can switch to a regular file and manually unlink it in an ensure to be extra super safe.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect that if the file was flushed after write the shell command should be able to read it then, but I haven't tried.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH I think this is the simplest solution. The GC should take care of unlinking at the appropriate time, but I'll add file.unlink if file in an ensure just in case.

end

def run_kubectl(*args)
raise FatalDeploymentError, "Namespace missing for namespaced command" if @namespace.blank?
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not check this on the constructor?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is copied from another place where it wouldn't make sense in the constructor. :P

Really, it's a super-paranoid check to make sure we don't run commands without a context/namespace. In reality, it should be impossible to hit in production (several other things would have raised before we get here). But I don't feel strongly about where it goes and can move it.


def run_kubectl(*args)
raise FatalDeploymentError, "Namespace missing for namespaced command" if @namespace.blank?
raise KubectlError, "Explicit context is required to run this command" if @context.blank?
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

Copy link
Contributor

@mkobetic mkobetic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

otherwise LGTM

file.write(secret_yaml)
file.close

out, err, st = run_kubectl("apply", "--filename=#{file.path}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make sure the file is deleted too, would Tempfile.open work for this?

@KnVerey
Copy link
Contributor Author

KnVerey commented May 9, 2017

Updated

file = Tempfile.new(secret_name)
file.write(secret_yaml)
file.close

out, err, st = run_kubectl("apply", "--filename=#{file.path}")
KubernetesDeploy.logger.debug(out)
raise EjsonSecretError, err unless st.success?
ensure
file.unlink if file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this can actually error out in some circumstances, I'd be fine to rely on Tempfile to take care of this. But I'm fine either way

@KnVerey KnVerey requested a review from ibawt May 9, 2017 18:47
Copy link
Contributor

@ibawt ibawt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code lgtm and for the record I'm not against shelling out to kubectl

We're having auth problems with kubeclient on some clusters, and deploys did not depend on that gem until the provisioner was introduced. We still would prefer to use kubeclient for this in the long run.
@KnVerey KnVerey merged commit 0c89cef into master May 9, 2017
@KnVerey KnVerey deleted the ejson_kubectl branch May 9, 2017 19:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants