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

Warn about kubernetes minimum version #237

Merged
merged 6 commits into from
Jan 16, 2018
Merged

Warn about kubernetes minimum version #237

merged 6 commits into from
Jan 16, 2018

Conversation

Fattouche
Copy link
Contributor

This fixes #152.

To be completely honest I have no idea if this is what you were looking for. Please feel free to tell me I am completely wrong 👍 , also any pointers in the right direction would be much appreciated :)

@Fattouche Fattouche requested a review from KnVerey January 12, 2018 16:49
Copy link
Contributor

@KnVerey KnVerey left a comment

Choose a reason for hiding this comment

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

To be completely honest I have no idea if this is what you were looking for.

This is definitely on the right track! We should also add the warning in the other two tasks, RunnerTask and RestartTask.

@@ -99,6 +99,7 @@ def initialize(namespace:, context:, current_sha:, template_dir:, logger:, kubec
@logger = logger
@kubectl = kubectl_instance
@bindings = bindings
@min_version = '1.6.0'
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be a constant IMO

@@ -340,6 +341,10 @@ def deploy_resources(resources, prune: false, verify:, record_summary: true)
return if resources.empty?
deploy_started_at = Time.now.utc

if server_version < Gem::Version.new(@min_version)
@logger.warn("Minimum cluster version requirement of #{@min_version} not met.")
end
Copy link
Contributor

Choose a reason for hiding this comment

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

deploy_resources actually gets called several times during the deploy process. Let's check this during the "Initializing deploy" phase. I'm thinking confirm_cluster_reachable would be an appropriate point.

That message looks good, but I'd suggest adding something about what the requirement means, i.e. that kubernetes-deploy is not tested against earlier versions of Kubernetes and may not work as expected.

Copy link
Contributor

Choose a reason for hiding this comment

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

Btw one way to 🎩 this would be to start an old version of minikube and run PRINT_LOGS=1 bundle exec ruby -I test test/integration/kubernetes_deploy_test.rb -n/full_hello/.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I was wondering how I could test this stuff!

@@ -19,6 +20,10 @@ def initialize(deployment_name, response)
HTTP_OK_RANGE = 200..299
ANNOTATION = "shipit.shopify.io/restart"

def server_version
kubectl.server_version
Copy link
Contributor Author

@Fattouche Fattouche Jan 15, 2018

Choose a reason for hiding this comment

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

I don't know how to go about getting the server_version in these tasks that don't already have kubectl defined. Is it okay to require Kubectl.rb and then just define kubectl like its done in deploy_task:

def kubectl
       @kubectl ||= Kubectl.new(namespace: @namespace, context: @context, logger: @logger, 
       log_failure_by_default: true)
end

I guess where my knowledge falls short is during run time. It looks like both restart_task and runner_task end up using deploy_task(atleast in testing) but does that mean that I can use the server_version function defined in deploy_task in the other classes? What I do now just seems like a lot of code duplication.
@KnVerey @stefanmb

Copy link
Contributor

Choose a reason for hiding this comment

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

looks like both restart_task and runner_task end up using deploy_task(atleast in testing)

I'm not sure what you're looking at here. The tasks share some tools (e.g. the resource watcher), but they're independent.

Is it okay to require Kubectl.rb and then just define kubectl like its done in deploy_task

Yes. What you have now now is the correct approach IMO. I personally wouldn't bother wrapping kubectl.server_version as server_version everywhere, but that doesn't matter at all. The reason the other two tasks don't already use kubectl extensively is that we were trying to stick to the Kubeclient gem instead. But I've checked pretty carefully, and it doesn't seem to expose any server metadata.

@Fattouche Fattouche requested a review from stefanmb January 15, 2018 18:59
@@ -432,6 +432,10 @@ def confirm_context_exists
end

def confirm_cluster_reachable
if server_version < Gem::Version.new(MIN_KUBE_VERSION)
Copy link
Contributor

Choose a reason for hiding this comment

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

You'll want to do this after the rest of the code in this method; the rest of the code confirms that the server actually exists, so we should do that before trying to ask it what its version is.

@@ -19,6 +20,10 @@ def initialize(deployment_name, response)
HTTP_OK_RANGE = 200..299
ANNOTATION = "shipit.shopify.io/restart"

def server_version
kubectl.server_version
Copy link
Contributor

Choose a reason for hiding this comment

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

looks like both restart_task and runner_task end up using deploy_task(atleast in testing)

I'm not sure what you're looking at here. The tasks share some tools (e.g. the resource watcher), but they're independent.

Is it okay to require Kubectl.rb and then just define kubectl like its done in deploy_task

Yes. What you have now now is the correct approach IMO. I personally wouldn't bother wrapping kubectl.server_version as server_version everywhere, but that doesn't matter at all. The reason the other two tasks don't already use kubectl extensively is that we were trying to stick to the Kubeclient gem instead. But I've checked pretty carefully, and it doesn't seem to expose any server metadata.


if server_version < Gem::Version.new(MIN_KUBE_VERSION)
@logger.warn("Minimum cluster version requirement of #{MIN_KUBE_VERSION} not met. "\
"Using #{server_version} could result in unexpected behavior as it is no longer tested against")
Copy link
Contributor

Choose a reason for hiding this comment

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

You could make a common method (maybe KubernetesDeploy::Errors.server_version_warning(server_version)?) that all three tasks could call to avoid repeating the full string everywhere.

@@ -1,6 +1,7 @@
# frozen_string_literal: true

module KubernetesDeploy
MIN_KUBE_VERSION = '1.6.0'
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd suggest putting this directly in kubernetes-deploy.rb since you're defining it on KubernetesDeploy, not on KubernetesDeploy::Kubectl.

def initialize(namespace:, context:, logger:)
@logger = logger
@namespace = namespace
@kubeclient = build_v1_kubeclient(context)
@context = context
@kubectl = nil
Copy link
Contributor

Choose a reason for hiding this comment

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

This won't do anything

@@ -8,4 +8,12 @@ def initialize(name, context)
super("Namespace `#{name}` not found in context `#{context}`")
end
end
class Errors
def self.server_version_warning(server_version, logger)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does it make sense to put this inside its own Errors class, would it be sufficient to just keep it in the errors module to stay with the library(for module) and object(for class) model? This is the only time I have really written any Ruby apart from tutorials so I am not sure about this code architecture.
@KnVerey

Copy link
Contributor

Choose a reason for hiding this comment

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

The bindings parser is an example of a pattern you can use when instances don't really make sense: Make Errors a module that extend self. There's no state to hold here, so making it a module makes sense to me. What I had in mind in suggesting it could go in Errors was more extracting the message only though (i.e. it would be a constant, except that we need to pass in the actual server version):

def server_version_warning(server_version)
  "Minimum cluster version requirement of #{MIN_KUBE_VERSION} not met. "\
  "Using #{server_version} could result in unexpected behavior as it is no longer tested against"
end

An alternative if you want to extract everything you've got here would be to put the method in the Kubectl class and call it something like validate_server_version. That works for me too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After reading up on the idea of extending self in a module instead of self.method inside a class you are totally right! Thanks for the tip 👍

@@ -441,6 +441,7 @@ def confirm_cluster_reachable
end
end
raise FatalDeploymentError, "Failed to reach server for #{@context}" unless success
KubernetesDeploy::Errors.server_version_warning(server_version, @logger)
Copy link
Contributor

Choose a reason for hiding this comment

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

Since the current class here is also namespaced inside KubernetesDeploy, you don't need the prefix here

@@ -8,4 +8,12 @@ def initialize(name, context)
super("Namespace `#{name}` not found in context `#{context}`")
end
end
class Errors
def self.server_version_warning(server_version, logger)
Copy link
Contributor

Choose a reason for hiding this comment

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

The bindings parser is an example of a pattern you can use when instances don't really make sense: Make Errors a module that extend self. There's no state to hold here, so making it a module makes sense to me. What I had in mind in suggesting it could go in Errors was more extracting the message only though (i.e. it would be a constant, except that we need to pass in the actual server version):

def server_version_warning(server_version)
  "Minimum cluster version requirement of #{MIN_KUBE_VERSION} not met. "\
  "Using #{server_version} could result in unexpected behavior as it is no longer tested against"
end

An alternative if you want to extract everything you've got here would be to put the method in the Kubectl class and call it something like validate_server_version. That works for me too.

@Fattouche Fattouche merged commit ef200ee into master Jan 16, 2018
@Fattouche Fattouche deleted the warn_kube_version branch January 16, 2018 21:47
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.

Enforce minimum kubernetes version
2 participants