kube_cluster 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release.yml +43 -0
  3. data/.github/workflows/tag-gem-version-bump.yml +47 -0
  4. data/.gitignore +2 -0
  5. data/Gemfile.lock +48 -52
  6. data/bin/console +3 -0
  7. data/bin/dev +4 -0
  8. data/docker-compose.yml +26 -0
  9. data/examples/01-basic-redis-pod/manifest.rb +60 -0
  10. data/examples/02-manifest-with-middleware/manifest.rb +37 -0
  11. data/examples/02-manifest-with-middleware/middleware/labels.rb +4 -0
  12. data/examples/02-manifest-with-middleware/middleware/namespace.rb +4 -0
  13. data/examples/02-manifest-with-middleware/templates/config_map.rb +13 -0
  14. data/examples/02-manifest-with-middleware/templates/deployment.rb +59 -0
  15. data/examples/02-manifest-with-middleware/templates/horizontal_pod_autoscaler.rb +30 -0
  16. data/examples/02-manifest-with-middleware/templates/ingress.rb +38 -0
  17. data/examples/02-manifest-with-middleware/templates/service.rb +12 -0
  18. data/examples/03-app-with-database/demo.rb +87 -0
  19. data/examples/03-app-with-database/helpers.rb +18 -0
  20. data/examples/03-app-with-database/my_app.rb +45 -0
  21. data/examples/03-app-with-database/postgresql.rb +81 -0
  22. data/examples/03-app-with-database/ruby_on_rails.rb +31 -0
  23. data/flake.lock +3 -3
  24. data/flake.nix +6 -0
  25. data/kube_cluster.gemspec +3 -1
  26. data/lib/kube/cli/cluster.rb +41 -0
  27. data/lib/kube/cluster/connection.rb +18 -0
  28. data/lib/kube/cluster/instance.rb +21 -0
  29. data/lib/kube/cluster/manifest.rb +25 -0
  30. data/lib/kube/cluster/middleware/annotations.rb +32 -0
  31. data/lib/kube/cluster/middleware/hpa_for_deployment.rb +111 -0
  32. data/lib/kube/cluster/middleware/ingress_for_service.rb +91 -0
  33. data/lib/kube/cluster/middleware/labels.rb +59 -0
  34. data/lib/kube/cluster/middleware/namespace.rb +31 -0
  35. data/lib/kube/cluster/middleware/pod_anti_affinity.rb +61 -0
  36. data/lib/kube/cluster/middleware/resource_preset.rb +64 -0
  37. data/lib/kube/cluster/middleware/security_context.rb +84 -0
  38. data/lib/kube/cluster/middleware/service_for_deployment.rb +71 -0
  39. data/lib/kube/cluster/middleware/stack.rb +43 -0
  40. data/lib/kube/cluster/middleware.rb +69 -0
  41. data/lib/kube/cluster/resource/dirty_tracking.rb +113 -0
  42. data/lib/kube/cluster/resource/persistence.rb +67 -0
  43. data/lib/kube/cluster/resource.rb +99 -0
  44. data/lib/kube/cluster/version.rb +1 -1
  45. data/lib/kube/cluster.rb +34 -7
  46. data/lib/kube/errors.rb +57 -0
  47. metadata +69 -17
  48. data/Rakefile +0 -11
  49. data/TREE_PLAN.md +0 -513
  50. data/bin/generate-command-schema-v1 +0 -44
  51. data/data/kubectl-command-tree-v1-minimal.json +0 -125
  52. data/data/kubectl-command-tree-v1.json +0 -1469
  53. data/examples/quick-repl/docker-compose.yml +0 -52
  54. data/exe/kube_cluster +0 -6
  55. data/lib/kube/cluster/command_node.rb +0 -89
  56. data/lib/kube/cluster/ctl.rb +0 -33
  57. data/lib/kube/cluster/query_builder.rb +0 -35
  58. data/lib/kube/cluster/resource_selector.rb +0 -19
  59. data/lib/kube/cluster/tree_node.rb +0 -51
@@ -1,52 +0,0 @@
1
- # to run define K3S_TOKEN, K3S_VERSION is optional, eg:
2
- # K3S_TOKEN=${RANDOM}${RANDOM}${RANDOM} docker-compose up
3
-
4
- services:
5
-
6
- server:
7
- image: "rancher/k3s:${K3S_VERSION:-latest}"
8
- command: server
9
- tmpfs:
10
- - /run
11
- - /var/run
12
- ulimits:
13
- nproc: 65535
14
- nofile:
15
- soft: 65535
16
- hard: 65535
17
- privileged: true
18
- restart: always
19
- environment:
20
- - K3S_TOKEN=${K3S_TOKEN:?err}
21
- - K3S_KUBECONFIG_OUTPUT=/output/kubeconfig.yaml
22
- - K3S_KUBECONFIG_MODE=666
23
- volumes:
24
- #- k3s-server:/var/lib/rancher/k3s
25
- # This is just so that we get the kubeconfig file out
26
- - .:/output
27
- ports:
28
- - 6443:6443 # Kubernetes API Server
29
- - 80:80 # Ingress controller port 80
30
- - 443:443 # Ingress controller port 443
31
-
32
- #agent:
33
- # image: "rancher/k3s:${K3S_VERSION:-latest}"
34
- # tmpfs:
35
- # - /run
36
- # - /var/run
37
- # ulimits:
38
- # nproc: 65535
39
- # nofile:
40
- # soft: 65535
41
- # hard: 65535
42
- # privileged: true
43
- # restart: always
44
- # environment:
45
- # - K3S_URL=https://server:6443
46
- # - K3S_TOKEN=${K3S_TOKEN:?err}
47
- # volumes:
48
- # - k3s-agent:/var/lib/rancher/k3s
49
-
50
- #volumes:
51
- # k3s-server: {}
52
- # k3s-agent: {}
data/exe/kube_cluster DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require_relative "../lib/kube/cluster"
5
-
6
- puts "hello from kube_cluster"
@@ -1,89 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kube
4
- module Cluster
5
- class CommandNode
6
- include Enumerable
7
-
8
- BLANK_DATA = { commands: [], resource: nil, args: [], flags: {} }.freeze
9
-
10
- attr_reader :command_data
11
-
12
- def initialize(current_node:, command_data: BLANK_DATA)
13
- @current_node = current_node
14
- @command_data = command_data
15
- end
16
-
17
- def flag(key, value = nil)
18
- self.class.new(
19
- current_node: @current_node,
20
- command_data: @command_data.merge(
21
- flags: @command_data[:flags].merge(key.to_s.tr("_", "-") => value)
22
- )
23
- )
24
- end
25
-
26
- def each(&block)
27
- to_a.each(&block)
28
- end
29
-
30
- def to_a
31
- QueryBuilder.new(@command_data).to_a
32
- end
33
-
34
- def to_s
35
- QueryBuilder.new(@command_data).to_s
36
- end
37
-
38
- def inspect
39
- "#<#{self.class.name} #{to_s}>"
40
- end
41
-
42
- def method_missing(name, *args, &block)
43
- segment = name.to_s.tr("_", "-")
44
- child = @current_node.children[segment]
45
-
46
- if child&.command?
47
- self.class.new(
48
- current_node: child,
49
- command_data: @command_data.merge(
50
- commands: @command_data[:commands] + [segment],
51
- args: @command_data[:args] + args.map(&:to_s)
52
- )
53
- )
54
- elsif child&.resource?
55
- self.class.new(
56
- current_node: child,
57
- command_data: @command_data.merge(
58
- resource: (@command_data[:resource] || ResourceSelector.new) + [segment],
59
- args: @command_data[:args] + args.map(&:to_s)
60
- )
61
- )
62
- elsif @current_node.resource? || @current_node.children.empty?
63
- # Leaf command or already in resource mode — free-form resource segment
64
- self.class.new(
65
- current_node: TreeNode.new(name: segment, type: :resource),
66
- command_data: @command_data.merge(
67
- resource: (@command_data[:resource] || ResourceSelector.new) + [segment],
68
- args: @command_data[:args] + args.map(&:to_s)
69
- )
70
- )
71
- elsif Enumerable.method_defined?(name)
72
- to_a.public_send(name, *args, &block)
73
- else
74
- super
75
- end
76
- end
77
-
78
- def respond_to_missing?(name, include_private = false)
79
- segment = name.to_s.tr("_", "-")
80
-
81
- @current_node.children.key?(segment) ||
82
- @current_node.resource? ||
83
- @current_node.children.empty? ||
84
- Enumerable.method_defined?(name) ||
85
- super
86
- end
87
- end
88
- end
89
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "json"
4
-
5
- module Kube
6
- module Cluster
7
- class Ctl
8
- GEM_ROOT = File.expand_path("../../..", __dir__)
9
-
10
- COMMAND_TREE = JSON.parse(
11
- File.read(File.join(GEM_ROOT, "data", "kubectl-command-tree-v1-minimal.json"))
12
- )
13
-
14
- ROOT = TreeNode.new(
15
- name: "kubectl",
16
- type: :command,
17
- children: TreeNode.build(COMMAND_TREE)
18
- )
19
-
20
- def method_missing(name, *args, &block)
21
- CommandNode.new(current_node: ROOT).public_send(name, *args, &block)
22
- end
23
-
24
- def respond_to_missing?(name, include_private = false)
25
- CommandNode.new(current_node: ROOT).respond_to?(name) || super
26
- end
27
-
28
- def inspect
29
- "#<#{self.class.name}>"
30
- end
31
- end
32
- end
33
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "open3"
4
-
5
- module Kube
6
- module Cluster
7
- class QueryBuilder
8
- def initialize(command_data)
9
- @commands = command_data[:commands] || []
10
- @resource = command_data[:resource]
11
- @args = command_data[:args] || []
12
- @flags = command_data[:flags] || {}
13
- end
14
-
15
- def to_s
16
- ["kubectl", *@commands, *resource_arg, *@args, *rendered_flags].join(" ")
17
- end
18
-
19
- def to_a
20
- stdout, _status = Open3.capture2("kubectl", *@commands, *resource_arg, *@args, *rendered_flags)
21
- stdout.lines.map(&:chomp)
22
- end
23
-
24
- private
25
-
26
- def resource_arg
27
- @resource ? [@resource.to_s] : []
28
- end
29
-
30
- def rendered_flags
31
- @flags.flat_map { |k, v| v.nil? ? ["--#{k}"] : ["--#{k}", v.to_s] }
32
- end
33
- end
34
- end
35
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kube
4
- module Cluster
5
- class ResourceSelector < Array
6
- def +(other)
7
- self.class.new(super)
8
- end
9
-
10
- def to_s
11
- join(".")
12
- end
13
-
14
- def to_regex
15
- Regexp.new(map { |s| Regexp.escape(s) }.join('.*\.'))
16
- end
17
- end
18
- end
19
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kube
4
- module Cluster
5
- class TreeNode
6
- # Commands whose leaf children are resource types.
7
- # Non-leaf children (those with their own subtree) remain commands.
8
- RESOURCE_PARENTS = %w[
9
- create
10
- create/secret
11
- create/service
12
- top
13
- ].freeze
14
-
15
- attr_reader :name, :type, :children
16
-
17
- def initialize(name:, type:, children: {})
18
- @name = name.freeze
19
- @type = type
20
- @children = children.freeze
21
- end
22
-
23
- def command? = type == :command
24
- def resource? = type == :resource
25
-
26
- # Recursively build a children hash of TreeNodes from the parsed JSON.
27
- # parent_path tracks position in the tree to determine child types.
28
- def self.build(hash, parent_path: nil)
29
- hash.each_with_object({}) do |(key, subtree), children|
30
- name = key.to_s
31
- current_path = [parent_path, name].compact.join("/")
32
- leaf = subtree.empty?
33
-
34
- # Under a resource parent, leaf nodes are resources, non-leaves are commands.
35
- # Everywhere else, everything is a command.
36
- child_type = if RESOURCE_PARENTS.include?(parent_path.to_s) && leaf
37
- :resource
38
- else
39
- :command
40
- end
41
-
42
- children[name] = new(
43
- name: name,
44
- type: child_type,
45
- children: build(subtree, parent_path: current_path)
46
- )
47
- end
48
- end
49
- end
50
- end
51
- end