class Biosphere::Kube::Client
Public Class Methods
new(hostname, ssl_options)
click to toggle source
# File lib/biosphere/kube.rb, line 109 def initialize(hostname, ssl_options) @clients = [] @clients << ::Kubeclient::Client.new("#{hostname}/api" , "v1", ssl_options: ssl_options) @clients << ::Kubeclient::Client.new("#{hostname}/apis/apps/" , "v1beta1", ssl_options: ssl_options) @clients << ::Kubeclient::Client.new("#{hostname}/apis/extensions/" , "v1beta1", ssl_options: ssl_options) @clients << ::Kubeclient::Client.new("#{hostname}/apis/batch/" , "v2alpha1", ssl_options: ssl_options) @clients << ::Kubeclient::Client.new("#{hostname}/apis/storage.k8s.io/" , "v1", ssl_options: ssl_options) @clients << ::Kubeclient::Client.new("#{hostname}/apis/autoscaling/" , "v1", ssl_options: ssl_options) @clients.each do |c| begin c.discover rescue KubeException => e puts "Could not discover api #{c.api_endpoint} - maybe this kube version is too old." end end end
Public Instance Methods
apply_resource(kuberesource)
click to toggle source
Applies the KubeResource
into the api server
The update process has the following sequence:
1) Try to fetch the resource to check if the resource is already there 2.1) If a new resource: issue a POST 2.2) If resource exists: merge existing resource with the KubeResource and issue a PUT (update)
# File lib/biosphere/kube.rb, line 238 def apply_resource(kuberesource) resource = kuberesource.document name = resource["metadata"]["name"] responses = [] not_found = false begin response = get(resource) rescue RestClient::NotFound => e not_found = true end if not_found begin response = post(resource) puts "Created resource #{response[:resource]}" responses << response rescue RestClient::NotFound => e pp e pp JSON.parse(e.response.body) puts "404 when applying resources might mean one of the following:" puts "\t * You're trying to apply a non-namespaced manifest." puts "\t Confirm if your manifests metadata should contain a namespace field or not" rescue RestClient::UnprocessableEntity => e pp e pp JSON.parse(e.response.body) end else puts "Updating resource #{response[:resource]}" # Get the current full resource from apiserver current_resource = response[:body] update_resource = kuberesource.merge_for_put(current_resource) begin responses << put(update_resource) rescue RestClient::BadRequest => e handle_bad_request(client, e, body, ns_prefix, resource_name) raise e rescue RestClient::Exception => e puts "Error updating resource: #{e} #{e.class}" pp JSON.parse(e.response) end return responses end end
get(resource)
click to toggle source
# File lib/biosphere/kube.rb, line 192 def get(resource) name = resource["metadata"]["name"] client = get_client(resource) resource_name = get_resource_name(resource) if !client raise ArgumentError, "Unknown resource #{resource["kind"]} of #{name} for kubernetes. Maybe this is in a new extension api?" end ns_prefix = client.build_namespace_prefix(resource["metadata"]["namespace"]) key = ns_prefix + resource_name + "/#{name}" ret = client.rest_client[key].get(client.instance_variable_get("@headers")) return { action: :get, resource: key, body: JSON.parse(ret.body) } end
get_client(resource)
click to toggle source
# File lib/biosphere/kube.rb, line 139 def get_client(resource) kind = resource["kind"].underscore_case @clients.each do |c| if c.instance_variable_get("@api_group") + c.instance_variable_get("@api_version") == resource["apiVersion"] return c end end return nil end
get_resource_name(resource)
click to toggle source
# File lib/biosphere/kube.rb, line 128 def get_resource_name(resource) resource_name = nil kind = resource["kind"].underscore_case @clients.each do |c| if c.instance_variable_get("@entities")[kind] return c.instance_variable_get("@entities")[kind].resource_name end end return nil end
handle_bad_request(client, e, body, ns_prefix, resource_name)
click to toggle source
# File lib/biosphere/kube.rb, line 299 def handle_bad_request(client, e, body, ns_prefix, resource_name) puts "Error calling API (on RestClient::BadRequest rescue): #{e}" puts "rest_client: #{ns_prefix + resource_name}, client: #{client.rest_client[ns_prefix + resource_name]}" begin msg = JSON.parse(e.http_body) if msg["message"] m = msg["message"].match(/\[pos ([0-9]+?)\]:\s?(.+)/) if m error_pos = m[1].to_i if error_pos < body.length # Find the line number where the error is line_number = 0 for pos in 0..body.length - 1 if body[pos] == "\n" line_number += 1 end if pos >= m[1].to_i break end end print_error_location(body.split("\n"), line_number) end end end rescue puts "Error message from body #{e.http_body}" end end
post(resource)
click to toggle source
# File lib/biosphere/kube.rb, line 149 def post(resource) name = resource["metadata"]["name"] client = get_client(resource) resource_name = get_resource_name(resource) if !client raise ArgumentError, "Unknown resource #{resource[:kind]} of #{name} for kubernetes. Maybe this is in a new extension api?" end ns_prefix = client.build_namespace_prefix(resource["metadata"]["namespace"]) body = JSON.pretty_generate(resource.to_h) begin ret = client.rest_client[ns_prefix + resource_name].post(body, { 'Content-Type' => 'application/json' }.merge(client.instance_variable_get("@headers"))) rescue RestClient::MethodNotAllowed => e if !resource[:metadata][:namespace] puts "Error doing api call: #{e}".colorize(:red) puts "This might be because you did not specify namespace in your resource: #{resource[:metadata]}".colorize(:yellow) else puts "Error calling API (on RestClient::MethodNotAllowed): #{e}" end puts "rest_client: #{ns_prefix + resource_name}, client: #{client.rest_client[ns_prefix + resource_name]}" puts "Dumpin resource request:" pp body raise e rescue RestClient::BadRequest => e handle_bad_request(client, e, body, ns_prefix, resource_name) raise e rescue RestClient::Exception => e puts "Error calling API (on RestClient::Exception rescue): #{e}" puts "rest_client: #{ns_prefix + resource_name}, client: #{client.rest_client[ns_prefix + resource_name]}" puts "Dumpin resource request:" pp resource.to_h.to_json raise e end return { action: :post, resource: ns_prefix + resource_name + "/#{name}", body: JSON.parse(ret.body) } end
print_error_location(lines, linenumber)
click to toggle source
# File lib/biosphere/kube.rb, line 286 def print_error_location(lines, linenumber) start_line = [0, linenumber - 3].max end_line = [lines.length - 1, linenumber + 3].min lines[start_line..end_line].each_with_index do |line, num| num += start_line if num == linenumber STDERR.printf("%04d> %s\n".red, num, line) else STDERR.printf("%04d| %s\n", num, line) end end end
put(resource)
click to toggle source
# File lib/biosphere/kube.rb, line 211 def put(resource) name = resource["metadata"]["name"] client = get_client(resource) resource_name = get_resource_name(resource) if !client raise ArgumentError, "Unknown resource #{resource["kind"]} of #{name} for kubernetes. Maybe this is in a new extension api?" end ns_prefix = client.build_namespace_prefix(resource["metadata"]["namespace"]) key = ns_prefix + resource_name + "/#{name}" ret = client.rest_client[key].put(resource.to_h.to_json, { 'Content-Type' => 'application/json' }.merge(client.instance_variable_get("@headers"))) return { action: :put, resource: key, body: JSON.parse(ret.body) } end