Module: Kube::Schema

Defined in:
lib/kube/schema.rb,
lib/kube/schema/version.rb,
lib/kube/schema/instance.rb,
lib/kube/schema/manifest.rb,
lib/kube/schema/resource.rb

Defined Under Namespace

Classes: Instance, Manifest, Resource

Constant Summary collapse

GEM_ROOT =
File.expand_path("../..", __dir__).freeze
SCHEMAS_DIR =
File.join(GEM_ROOT, "schemas").freeze
DEFAULT_VERSION =
"1.34"
VERSION =
"1.3.4"

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.custom_schemasObject (readonly)

Custom schemas registered via Kube::Schema.register. Keys are kind strings, values are { schema:, defaults: } hashes.



32
33
34
# File 'lib/kube/schema.rb', line 32

def custom_schemas
  @custom_schemas
end

.schema_versionObject

Set a default Kubernetes version for bare lookups like Kube::Schema. When nil, the DEFAULT_VERSION is used.



28
29
30
# File 'lib/kube/schema.rb', line 28

def schema_version
  @schema_version
end

Class Method Details

.[](key) ⇒ Object

Kube::Schema => cached Instance (supports [“Deployment”] chaining) Kube::Schema => Resource via the default version



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/kube/schema.rb', line 97

def [](key)
  if key.start_with?("v") && Gem::Version.correct?(key.sub("v", ""))
    raise Kube::IncorrectVersionFormat,
      "\nDon't preface the version with a \"v\"." \
      "\nUse Kube::Schema[\"#{key.sub("v", "")}\"] instead."
  end

  if Gem::Version.correct?(key)
    if has_version?(key)
      @instances[key] ||= Instance.new(key)
    else
      raise Kube::UnknownVersionError.new(
        "\n#{key} is an unknown version..." +
        "\nAvailable: #{schema_versions.join(", ")}"
      )
    end
  else
    version = schema_version || DEFAULT_VERSION
    @instances[version] ||= Instance.new(version)
    @instances[version][key]
  end
end

.has_version?(version) ⇒ Boolean

Returns:

  • (Boolean)


157
158
159
# File 'lib/kube/schema.rb', line 157

def has_version?(version)
  schema_versions.include?(version)
end

.latest_versionObject

The latest Kubernetes version available in the schemas directory.



153
154
155
# File 'lib/kube/schema.rb', line 153

def latest_version
  schema_versions.last
end

.parse(hash) ⇒ Resource

Build a typed Resource from a raw hash.

Looks up the “kind” key in the hash and resolves it to the correct Resource subclass via the schema registry. The hash may use string or symbol keys.

Kube::Schema.parse("kind" => "Deployment", "apiVersion" => "apps/v1")
Kube::Schema.parse(kind: "Pod", apiVersion: "v1", metadata: { name: "web" })

Parameters:

  • hash (Hash)

    a Kubernetes resource hash with at least a “kind” key

Returns:

  • (Resource)

    a schema-validated Resource instance

Raises:

  • (ArgumentError)

    if the hash is nil, not a Hash, or missing “kind”



132
133
134
135
136
137
138
139
140
# File 'lib/kube/schema.rb', line 132

def parse(hash)
  raise ArgumentError, "Expected a Hash, got #{hash.class}" unless hash.is_a?(Hash)

  kind = hash["kind"] || hash[:kind]
  raise ArgumentError, "Hash must contain a \"kind\" key" if kind.nil?

  resource_class = self[kind]
  resource_class.new(hash)
end

.register(kind, schema:, api_version:) ⇒ Object

Register a standalone JSON Schema for a custom resource kind.

This lets users add CRD schemas from any source — for example, the datreeio/CRDs-catalog, operator repos, or their own CRDs. Registered kinds take precedence over built-in definitions.

Examples:

Register from a local file

Kube::Schema.register("Certificate",
  schema: "schemas/cert-manager.io/certificate_v1.json",
  api_version: "cert-manager.io/v1"
)

Register from Chart#crds

chart.crds.each do |crd|
  s = crd.to_json_schema
  Kube::Schema.register(s[:kind], schema: s[:schema], api_version: s[:api_version])
end

Parameters:

  • kind (String)

    The Kubernetes Kind (e.g. “Certificate”)

  • schema (Hash, String, Pathname)

    JSON Schema as a Hash, a JSON string, or a file path to a .json file

  • api_version (String)

    The apiVersion (e.g. “cert-manager.io/v1”)



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/kube/schema.rb', line 57

def register(kind, schema:, api_version:)
  require "json"
  require "json_schemer"

  parsed = case schema
    when Hash
      schema
    when String, Pathname
      path = schema.to_s
      if File.exist?(path)
        JSON.parse(File.read(path))
      else
        JSON.parse(path)
      end
    else
      raise ArgumentError,
        "schema must be a Hash, a JSON string, or a file path — got #{schema.class}"
    end

  @custom_schemas[kind] = {
    schema: JSONSchemer.schema(parsed),
    defaults: { "apiVersion" => api_version, "kind" => kind }.freeze
  }

  # Invalidate cached resource classes on all instances so the
  # new registration takes effect immediately.
  @instances.each_value { |inst| inst.send(:clear_resource_cache!) }

  kind
end

.reset_custom_schemas!Object

Remove all custom schema registrations. Useful for test teardown or resetting state.



90
91
92
93
# File 'lib/kube/schema.rb', line 90

def reset_custom_schemas!
  @custom_schemas.clear
  @instances.each_value { |inst| inst.send(:clear_resource_cache!) }
end

.schema_versionsArray<String>

Available Kubernetes versions, read from the local schemas directory.

Returns:

  • (Array<String>)

    sorted version strings like [“1.19”, “1.20”, …]



145
146
147
148
149
150
# File 'lib/kube/schema.rb', line 145

def schema_versions
  @schema_versions ||=
    Dir.glob(File.join(SCHEMAS_DIR, "v*.json")).map do |file_path|
      File.basename(file_path, ".json").sub(/\Av/, "")
    end.sort_by { Gem::Version.new(_1) }
end