class Krane::ClusterResourceDiscovery

Public Class Methods

new(task_config:, namespace_tags: []) click to toggle source
# File lib/krane/cluster_resource_discovery.rb, line 8
def initialize(task_config:, namespace_tags: [])
  @task_config = task_config
  @namespace_tags = namespace_tags
  @api_path_cache = {}
end

Public Instance Methods

crds() click to toggle source
# File lib/krane/cluster_resource_discovery.rb, line 14
def crds
  @crds ||= fetch_crds.map do |cr_def|
    CustomResourceDefinition.new(namespace: namespace, context: context, logger: logger,
      definition: cr_def, statsd_tags: @namespace_tags)
  end
end
fetch_mutating_webhook_configurations() click to toggle source
# File lib/krane/cluster_resource_discovery.rb, line 40
def fetch_mutating_webhook_configurations
  command = %w(get mutatingwebhookconfigurations)
  raw_json, err, st = kubectl.run(*command, output: "json", attempts: 5, use_namespace: false)
  if st.success?
    JSON.parse(raw_json)["items"].map do |definition|
      Krane::MutatingWebhookConfiguration.new(namespace: namespace, context: context, logger: logger,
        definition: definition, statsd_tags: @namespace_tags)
    end
  else
    raise FatalKubeAPIError, "Error retrieving mutatingwebhookconfigurations: #{err}"
  end
end
fetch_resources(namespaced: false) click to toggle source
# File lib/krane/cluster_resource_discovery.rb, line 30
def fetch_resources(namespaced: false)
  responses = Concurrent::Hash.new
  Krane::Concurrency.split_across_threads(api_paths) do |path|
    responses[path] = fetch_api_path(path)["resources"] || []
  end
  responses.flat_map do |path, resources|
    resources.map { |r| resource_hash(path, namespaced, r) }
  end.compact.uniq { |r| "#{r['apigroup']}/#{r['kind']}" }
end
prunable_resources(namespaced:) click to toggle source
# File lib/krane/cluster_resource_discovery.rb, line 21
def prunable_resources(namespaced:)
  black_list = %w(Namespace Node ControllerRevision)
  fetch_resources(namespaced: namespaced).map do |resource|
    next unless resource["verbs"].one? { |v| v == "delete" }
    next if black_list.include?(resource["kind"])
    [resource["apigroup"], resource["version"], resource["kind"]].compact.join("/")
  end.compact
end

Private Instance Methods

api_paths() click to toggle source
# File lib/krane/cluster_resource_discovery.rb, line 66
def api_paths
  @api_path_cache["/"] ||= begin
    raw_json, err, st = kubectl.run("get", "--raw", base_api_path, attempts: 5, use_namespace: false)
    paths = if st.success?
      JSON.parse(raw_json)["paths"]
    else
      raise FatalKubeAPIError, "Error retrieving raw path /: #{err}"
    end
    paths.select { |path| %r{^\/api.*\/v.*$}.match(path) }
  end
end
base_api_path() click to toggle source

During discovery, the api paths may not actually be at the root, so we must programatically find it.

# File lib/krane/cluster_resource_discovery.rb, line 56
def base_api_path
  @base_api_path ||= begin
    raw_response, err, st = kubectl.run("config", "view", "--minify", "--output",
      "jsonpath={.clusters[*].cluster.server}", attempts: 5, use_namespace: false)
    raise FatalKubeAPIError, "Error retrieving cluster url: #{err}" unless st.success?

    URI(raw_response).path.blank? ? "/" : URI(raw_response).path
  end
end
fetch_api_path(path) click to toggle source
# File lib/krane/cluster_resource_discovery.rb, line 78
def fetch_api_path(path)
  @api_path_cache[path] ||= begin
    raw_json, err, st = kubectl.run("get", "--raw", path, attempts: 2, use_namespace: false)
    if st.success?
      JSON.parse(raw_json)
    else
      logger.warn("Error retrieving api path: #{err}")
      {}
    end
  end
end
fetch_crds() click to toggle source
# File lib/krane/cluster_resource_discovery.rb, line 104
def fetch_crds
  raw_json, err, st = kubectl.run("get", "CustomResourceDefinition", output: "json", attempts: 5,
    use_namespace: false)
  if st.success?
    JSON.parse(raw_json)["items"]
  else
    raise FatalKubeAPIError, "Error retrieving CustomResourceDefinition: #{err}"
  end
end
kubectl() click to toggle source
# File lib/krane/cluster_resource_discovery.rb, line 114
def kubectl
  @kubectl ||= Kubectl.new(task_config: @task_config, log_failure_by_default: true)
end
resource_hash(path, namespaced, blob) click to toggle source
# File lib/krane/cluster_resource_discovery.rb, line 90
def resource_hash(path, namespaced, blob)
  return unless blob["namespaced"] == namespaced
  # skip sub-resources
  return if blob["name"].include?("/")
  path_regex = %r{(/apis?/)(?<group>[^/]*)/?(?<version>v.+)}
  match = path.match(path_regex)
  {
    "verbs" => blob["verbs"],
    "kind" => blob["kind"],
    "apigroup" => match[:group],
    "version" => match[:version],
  }
end