kozo 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +7 -2
- data/.kzignore +1 -0
- data/.overcommit.yml +1 -0
- data/.rspec +1 -0
- data/.rubocop.yml +44 -5
- data/CHANGELOG.md +5 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +156 -48
- data/LICENSE.md +1 -1
- data/README.md +28 -0
- data/Rakefile +3 -7
- data/bin/kozo +6 -2
- data/config/application.rb +3 -0
- data/config/dependencies.rb +4 -25
- data/kozo.gemspec +20 -5
- data/lib/core_ext/boolean.rb +12 -0
- data/lib/core_ext/nil_class.rb +11 -0
- data/lib/core_ext/string.rb +25 -0
- data/lib/kozo/backend.rb +81 -0
- data/lib/kozo/backends/git.rb +50 -0
- data/lib/kozo/backends/local.rb +41 -15
- data/lib/kozo/backends/memory.rb +26 -0
- data/lib/kozo/cli.rb +30 -9
- data/lib/kozo/command.rb +32 -0
- data/lib/kozo/commands/apply.rb +44 -0
- data/lib/kozo/commands/console.rb +15 -0
- data/lib/kozo/commands/import.rb +47 -0
- data/lib/kozo/commands/init.rb +15 -0
- data/lib/kozo/commands/plan.rb +29 -3
- data/lib/kozo/commands/refresh.rb +21 -0
- data/lib/kozo/commands/show.rb +15 -0
- data/lib/kozo/commands/state.rb +64 -0
- data/lib/kozo/commands/validate.rb +13 -0
- data/lib/kozo/commands/version.rb +13 -0
- data/lib/kozo/concerns/assignment.rb +17 -0
- data/lib/kozo/concerns/attributes.rb +99 -0
- data/lib/kozo/concerns/mark.rb +25 -0
- data/lib/kozo/concerns/track.rb +47 -0
- data/lib/kozo/configuration.rb +34 -7
- data/lib/kozo/dsl.rb +18 -12
- data/lib/kozo/error.rb +13 -0
- data/lib/kozo/logger.rb +8 -4
- data/lib/kozo/operation.rb +42 -0
- data/lib/kozo/operations/create.rb +29 -0
- data/lib/kozo/operations/destroy.rb +29 -0
- data/lib/kozo/operations/show.rb +12 -0
- data/lib/kozo/operations/update.rb +19 -0
- data/lib/kozo/options.rb +9 -1
- data/lib/kozo/parser.rb +35 -0
- data/lib/kozo/provider.rb +7 -1
- data/lib/kozo/providers/dummy/dependencies.rb +9 -0
- data/lib/kozo/providers/{null → dummy}/provider.rb +2 -6
- data/lib/kozo/providers/dummy/resource.rb +19 -0
- data/lib/kozo/providers/dummy/resources/dummy.rb +16 -0
- data/lib/kozo/providers/hcloud/dependencies.rb +13 -0
- data/lib/kozo/providers/hcloud/provider.rb +7 -1
- data/lib/kozo/providers/hcloud/resource.rb +46 -1
- data/lib/kozo/providers/hcloud/resources/server.rb +29 -0
- data/lib/kozo/providers/hcloud/resources/ssh_key.rb +6 -2
- data/lib/kozo/resource.rb +110 -3
- data/lib/kozo/state.rb +25 -0
- data/lib/kozo/type.rb +15 -0
- data/lib/kozo/types/boolean.rb +30 -0
- data/lib/kozo/types/date.rb +20 -0
- data/lib/kozo/types/float.rb +17 -0
- data/lib/kozo/types/hash.rb +20 -0
- data/lib/kozo/types/integer.rb +17 -0
- data/lib/kozo/types/string.rb +17 -0
- data/lib/kozo/types/time.rb +18 -0
- data/lib/kozo/version.rb +1 -1
- data/lib/kozo.rb +13 -7
- metadata +195 -31
- data/.github/dependabot.yml +0 -14
- data/.github/workflows/ci.yml +0 -81
- data/bin/bundle +0 -118
- data/bin/console +0 -7
- data/bin/rspec +0 -28
- data/bin/version +0 -62
- data/lib/kozo/backends/base.rb +0 -31
- data/lib/kozo/commands/base.rb +0 -21
- data/lib/kozo/container.rb +0 -35
- data/lib/kozo/environment.rb +0 -27
- data/lib/kozo/providers/null/resource.rb +0 -11
- data/lib/kozo/providers/null/resources/null.rb +0 -13
- data/log/.keep +0 -0
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kozo
|
4
|
+
module Attributes
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
class_attribute :attribute_types, default: {}
|
9
|
+
|
10
|
+
def read_attribute(name)
|
11
|
+
value = instance_variable_get(:"@#{name}")
|
12
|
+
|
13
|
+
return value unless value.nil?
|
14
|
+
|
15
|
+
# Set default
|
16
|
+
instance_variable_set(:"@#{name}", (attribute_types[name][:default].dup || (attribute_types[name][:multiple] ? [] : nil)))
|
17
|
+
end
|
18
|
+
|
19
|
+
def write_attribute(name, value)
|
20
|
+
try(:track_change!, name, value)
|
21
|
+
|
22
|
+
value = if attribute_types[name][:multiple]
|
23
|
+
Array(value).map { |v| attribute_types[name][:type].cast(v) }
|
24
|
+
else
|
25
|
+
attribute_types[name][:type].cast(value)
|
26
|
+
end
|
27
|
+
|
28
|
+
instance_variable_set(:"@#{name}", value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# rubocop:disable Metrics/BlockLength
|
33
|
+
class_methods do
|
34
|
+
def inherited(sub_class)
|
35
|
+
super
|
36
|
+
|
37
|
+
sub_class.attribute_types = attribute_types.clone
|
38
|
+
end
|
39
|
+
|
40
|
+
def attribute(name, **options)
|
41
|
+
name = name.to_sym
|
42
|
+
type = Type.lookup(options.fetch(:type, :string))
|
43
|
+
|
44
|
+
try(:track, name)
|
45
|
+
|
46
|
+
options = attribute_types[name] = {
|
47
|
+
multiple: !!options[:multiple],
|
48
|
+
attribute: !!options.fetch(:attribute, true),
|
49
|
+
argument: !!options.fetch(:argument, true),
|
50
|
+
type: type,
|
51
|
+
default: options[:default],
|
52
|
+
}
|
53
|
+
|
54
|
+
# Define getter
|
55
|
+
unless method_defined? name
|
56
|
+
define_method(name) { read_attribute(name) }
|
57
|
+
define_method(:"#{name}?") { !!read_attribute(name) }
|
58
|
+
end
|
59
|
+
|
60
|
+
# Set visibility to public if it's an attribute
|
61
|
+
options[:attribute] ? public(name) : private(name)
|
62
|
+
|
63
|
+
# Define setter
|
64
|
+
define_method(:"#{name}=") { |value| write_attribute(name, value) } unless method_defined? :"#{name}="
|
65
|
+
|
66
|
+
# Set visibility to public if it's an argument
|
67
|
+
options[:argument] ? public(:"#{name}=") : private(:"#{name}=")
|
68
|
+
end
|
69
|
+
|
70
|
+
def attribute_names
|
71
|
+
@attribute_names ||= attribute_types
|
72
|
+
.select { |_k, v| v[:attribute] }
|
73
|
+
.keys
|
74
|
+
end
|
75
|
+
|
76
|
+
def argument_names
|
77
|
+
@argument_names ||= attribute_types
|
78
|
+
.select { |_k, v| v[:argument] }
|
79
|
+
.keys
|
80
|
+
end
|
81
|
+
end
|
82
|
+
# rubocop:enable Metrics/BlockLength
|
83
|
+
|
84
|
+
def attributes
|
85
|
+
attribute_names
|
86
|
+
.map { |name| [name, read_attribute(name)] }
|
87
|
+
.to_h
|
88
|
+
end
|
89
|
+
|
90
|
+
def arguments
|
91
|
+
argument_names
|
92
|
+
.map { |name| [name, read_attribute(name)] }
|
93
|
+
.to_h
|
94
|
+
end
|
95
|
+
|
96
|
+
delegate :attribute_names, to: :class
|
97
|
+
delegate :argument_names, to: :class
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kozo
|
4
|
+
module Mark
|
5
|
+
def mark_for_deletion!
|
6
|
+
@status = :delete
|
7
|
+
end
|
8
|
+
|
9
|
+
def marked_for_deletion?
|
10
|
+
@status == :delete
|
11
|
+
end
|
12
|
+
|
13
|
+
def mark_for_creation!
|
14
|
+
@status = :create
|
15
|
+
end
|
16
|
+
|
17
|
+
def marked_for_creation?
|
18
|
+
@status == :create
|
19
|
+
end
|
20
|
+
|
21
|
+
def unmark!
|
22
|
+
@status = nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kozo
|
4
|
+
module Track
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
class_attribute :trackables, default: Set.new
|
9
|
+
|
10
|
+
attr_reader :changes
|
11
|
+
|
12
|
+
def changed?
|
13
|
+
changes.any?
|
14
|
+
end
|
15
|
+
|
16
|
+
def clear_changes
|
17
|
+
@changes = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def restore_changes
|
21
|
+
changes.each { |key, (from, _to)| send(:"#{key}=", from) }
|
22
|
+
|
23
|
+
clear_changes
|
24
|
+
end
|
25
|
+
|
26
|
+
def track_change!(name, value)
|
27
|
+
changes[name] = [send(name), value] unless send(name) == value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class_methods do
|
32
|
+
def track(name)
|
33
|
+
trackables << name
|
34
|
+
|
35
|
+
define_method(:"#{name}_change") { changes[name] } unless method_defined? :"#{name}_change"
|
36
|
+
define_method(:"#{name}_changed?") { !!changes[name] } unless method_defined? :"#{name}_changed?"
|
37
|
+
define_method(:"#{name}_was") { changes.dig(name, 0) } unless method_defined? :"#{name}_was"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(...)
|
42
|
+
@changes = {}
|
43
|
+
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/kozo/configuration.rb
CHANGED
@@ -8,18 +8,45 @@ module Kozo
|
|
8
8
|
def initialize(directory)
|
9
9
|
@directory = directory
|
10
10
|
@providers = {}
|
11
|
-
@resources =
|
11
|
+
@resources = Set.new
|
12
12
|
end
|
13
13
|
|
14
14
|
def backend
|
15
|
-
@backend ||=
|
15
|
+
@backend ||= Kozo
|
16
|
+
.container
|
17
|
+
.resolve("backend.local", self, directory)
|
16
18
|
end
|
17
19
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
def changes
|
21
|
+
@changes ||= begin
|
22
|
+
# Copy resources in state
|
23
|
+
changes = backend
|
24
|
+
.state
|
25
|
+
.resources
|
26
|
+
.map(&:dup)
|
27
|
+
.each(&:clear_changes)
|
28
|
+
.each do |resource|
|
29
|
+
configured = resources.find { |r| r.address == resource.address }
|
30
|
+
|
31
|
+
# Assign updated attributes (mark for update)
|
32
|
+
resource.assign_attributes(configured&.attributes&.except(:id) || resource.attributes.except(:id).transform_values { nil })
|
33
|
+
|
34
|
+
# Mark for deletion
|
35
|
+
resource.mark_for_deletion! unless configured
|
36
|
+
end
|
37
|
+
|
38
|
+
# Append resources not in state
|
39
|
+
changes += resources
|
40
|
+
.reject { |r| backend.state.resources.any? { |res| res.address == r.address } }
|
41
|
+
.map { |r| r.class.new(state_name: r.state_name, **r.arguments) }
|
42
|
+
.each(&:mark_for_creation!)
|
43
|
+
|
44
|
+
changes
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
"directory: #{directory}"
|
23
50
|
end
|
24
51
|
end
|
25
52
|
end
|
data/lib/kozo/dsl.rb
CHANGED
@@ -13,7 +13,7 @@ module Kozo
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def backend(type)
|
16
|
-
backend = resolve(:backend, type)
|
16
|
+
backend = resolve(:backend, type, configuration)
|
17
17
|
|
18
18
|
yield backend if block_given?
|
19
19
|
|
@@ -25,28 +25,34 @@ module Kozo
|
|
25
25
|
|
26
26
|
yield provider if block_given?
|
27
27
|
|
28
|
-
|
28
|
+
provider.setup
|
29
|
+
|
30
|
+
configuration.providers[provider.provider_name] = provider
|
29
31
|
end
|
30
32
|
|
31
|
-
def resource(type,
|
32
|
-
resource = resolve(:resource, type
|
33
|
-
resource.
|
33
|
+
def resource(type, state_name)
|
34
|
+
resource = resolve(:resource, type)
|
35
|
+
resource.state_name = state_name
|
36
|
+
|
37
|
+
raise InvalidResource, "resource #{resource.address} already defined" if configuration.resources.include?(resource)
|
38
|
+
|
39
|
+
resource.provider = configuration.providers[resource.provider_name]
|
34
40
|
|
35
|
-
|
41
|
+
raise InvalidResource, "provider #{resource.provider_name} not configured" unless resource.provider
|
36
42
|
|
37
43
|
yield resource if block_given?
|
38
44
|
|
39
|
-
configuration.resources
|
45
|
+
configuration.resources << resource
|
40
46
|
end
|
41
47
|
|
42
48
|
private
|
43
49
|
|
44
|
-
def resolve(resource, type,
|
45
|
-
Kozo.logger.debug "Initializing #{resource} #{type} #{
|
50
|
+
def resolve(resource, type, *args)
|
51
|
+
Kozo.logger.debug "Initializing #{resource} #{type}#{" with options #{args.join(' ')}" if args.any?}"
|
46
52
|
|
47
|
-
Kozo.container.resolve("#{resource}.#{type}")
|
48
|
-
rescue Container::DependencyNotRegistered
|
49
|
-
|
53
|
+
Kozo.container.resolve("#{resource}.#{type}", *args)
|
54
|
+
rescue Dinja::Container::DependencyNotRegistered
|
55
|
+
raise InvalidResource, "unknown #{resource} type: #{type}"
|
50
56
|
end
|
51
57
|
end
|
52
58
|
end
|
data/lib/kozo/error.rb
ADDED
data/lib/kozo/logger.rb
CHANGED
@@ -12,18 +12,22 @@ module Kozo
|
|
12
12
|
private
|
13
13
|
|
14
14
|
def level
|
15
|
-
ENV.fetch("LOG_LEVEL", "info")
|
15
|
+
Kozo.options.verbose? ? "debug" : ENV.fetch("LOG_LEVEL", "info")
|
16
16
|
end
|
17
17
|
|
18
18
|
def formatter
|
19
|
-
|
19
|
+
Formatter.new
|
20
20
|
end
|
21
21
|
|
22
22
|
class Formatter < ::Logger::Formatter
|
23
23
|
def call(severity, _time, _progname, msg)
|
24
|
-
abort("#{File.basename($PROGRAM_NAME)}: #{msg[0].downcase}#{msg[1..]}") if severity == "FATAL"
|
24
|
+
abort("#{File.basename($PROGRAM_NAME)}: #{msg[0].downcase}#{msg[1..]}".white.on_red) if severity == "FATAL"
|
25
25
|
|
26
|
-
"#{msg}\n"
|
26
|
+
msg = "#{msg}\n"
|
27
|
+
msg = msg.yellow if severity == "DEBUG"
|
28
|
+
msg = msg.red if severity == "ERROR"
|
29
|
+
|
30
|
+
msg
|
27
31
|
end
|
28
32
|
end
|
29
33
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kozo
|
4
|
+
class Operation
|
5
|
+
attr_reader :resource
|
6
|
+
|
7
|
+
class_attribute :symbol, :display_symbol
|
8
|
+
|
9
|
+
def initialize(resource)
|
10
|
+
@resource = resource
|
11
|
+
end
|
12
|
+
|
13
|
+
def apply(_state)
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
resource_to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def resource_to_s
|
24
|
+
<<~DSL.chomp
|
25
|
+
#{"# #{resource.address}:".bold}
|
26
|
+
#{display_symbol} resource "#{resource.resource_name}", "#{resource.state_name}" do |r|
|
27
|
+
#{attributes_to_s}
|
28
|
+
end
|
29
|
+
|
30
|
+
DSL
|
31
|
+
end
|
32
|
+
|
33
|
+
def attributes_to_s
|
34
|
+
l = resource.attribute_names.map(&:length).max || 1
|
35
|
+
|
36
|
+
resource
|
37
|
+
.attributes
|
38
|
+
.map { |k, v| "#{resource.changes.key?(k) ? display_symbol : ' '} r.#{k.to_s.ljust(l)} = \"#{v.to_s.chomp.truncate(75)}\"" }
|
39
|
+
.join("\n ")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kozo
|
4
|
+
module Operations
|
5
|
+
class Create < Operation
|
6
|
+
self.symbol = :+
|
7
|
+
self.display_symbol = "+".green
|
8
|
+
|
9
|
+
def apply(state)
|
10
|
+
# Create resource in remote infrastructure
|
11
|
+
resource.create!
|
12
|
+
|
13
|
+
# Add resource to local state
|
14
|
+
state.resources << resource
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def attributes_to_s
|
20
|
+
l = resource.attribute_names.map(&:length).max || 1
|
21
|
+
|
22
|
+
resource
|
23
|
+
.attributes
|
24
|
+
.map { |k, v| "#{resource.changes.key?(k) ? display_symbol : ' '} r.#{k.to_s.ljust(l)} = #{v.blank? ? '(known after apply)' : "\"#{v.to_s.chomp.truncate(75)}\""}" }
|
25
|
+
.join("\n ")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kozo
|
4
|
+
module Operations
|
5
|
+
class Destroy < Operation
|
6
|
+
self.symbol = :-
|
7
|
+
self.display_symbol = "-".red
|
8
|
+
|
9
|
+
def apply(state)
|
10
|
+
# Destroy resource in remote infrastructure
|
11
|
+
resource.destroy!
|
12
|
+
|
13
|
+
# Delete resource from local state
|
14
|
+
state.resources.delete(resource)
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def attributes_to_s
|
20
|
+
l = resource.attribute_names.map(&:length).max || 1
|
21
|
+
|
22
|
+
resource
|
23
|
+
.attribute_names
|
24
|
+
.map { |k| "#{display_symbol} r.#{k.to_s.ljust(l)} = \"#{resource.send(:"#{k}_was").to_s.chomp.truncate(75)}\"" }
|
25
|
+
.join("\n ")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kozo
|
4
|
+
module Operations
|
5
|
+
class Update < Operation
|
6
|
+
self.symbol = :~
|
7
|
+
self.display_symbol = "~".yellow
|
8
|
+
|
9
|
+
def apply(state)
|
10
|
+
# Update resource in remote infrastructure
|
11
|
+
resource.update!
|
12
|
+
|
13
|
+
# Update resource in local state
|
14
|
+
state.resources.delete(resource)
|
15
|
+
state.resources << resource
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/kozo/options.rb
CHANGED
@@ -2,7 +2,11 @@
|
|
2
2
|
|
3
3
|
module Kozo
|
4
4
|
class Options
|
5
|
-
|
5
|
+
attr_accessor :help
|
6
|
+
|
7
|
+
def directory=(path)
|
8
|
+
@directory = File.expand_path(path)
|
9
|
+
end
|
6
10
|
|
7
11
|
def directory
|
8
12
|
@directory ||= Dir.pwd
|
@@ -12,6 +16,10 @@ module Kozo
|
|
12
16
|
directory.present?
|
13
17
|
end
|
14
18
|
|
19
|
+
def verbose=(value)
|
20
|
+
@verbose = value.present?
|
21
|
+
end
|
22
|
+
|
15
23
|
def verbose
|
16
24
|
@verbose ||= false
|
17
25
|
end
|
data/lib/kozo/parser.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kozo
|
4
|
+
class Parser
|
5
|
+
attr_reader :directory
|
6
|
+
|
7
|
+
def initialize(directory)
|
8
|
+
@directory = directory
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
configuration = Configuration.new(directory)
|
13
|
+
dsl = DSL.new(configuration)
|
14
|
+
|
15
|
+
Dir[File.join(directory, "main.kz"), File.join(directory, "**", "*.kz")]
|
16
|
+
.uniq
|
17
|
+
.reject { |file| ignores.any? { |ignore| file.include?(ignore) } }
|
18
|
+
.each { |file| dsl.instance_eval(File.read(file)) }
|
19
|
+
|
20
|
+
configuration
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def ignores
|
26
|
+
@ignores ||= begin
|
27
|
+
File
|
28
|
+
.readlines(File.join(directory, ".kzignore"))
|
29
|
+
.map(&:chomp)
|
30
|
+
rescue Errno::ENOENT
|
31
|
+
[]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/kozo/provider.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kozo
|
4
|
+
module Providers
|
5
|
+
module Dummy
|
6
|
+
class Resource < Kozo::Resource
|
7
|
+
self.provider_name = "dummy"
|
8
|
+
|
9
|
+
def refresh!; end
|
10
|
+
|
11
|
+
def create!; end
|
12
|
+
|
13
|
+
def destroy!; end
|
14
|
+
|
15
|
+
def update!; end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
register("provider.hcloud") do
|
4
|
+
Kozo::Providers::HCloud::Provider.new
|
5
|
+
end
|
6
|
+
|
7
|
+
register("resource.hcloud_ssh_key") do
|
8
|
+
Kozo::Providers::HCloud::Resources::SSHKey.new
|
9
|
+
end
|
10
|
+
|
11
|
+
register("resource.hcloud_server") do
|
12
|
+
Kozo::Providers::HCloud::Resources::Server.new
|
13
|
+
end
|
@@ -1,12 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "hcloud"
|
4
|
+
|
3
5
|
module Kozo
|
4
6
|
module Providers
|
5
7
|
module HCloud
|
6
8
|
class Provider < Kozo::Provider
|
7
9
|
attr_accessor :key
|
8
10
|
|
9
|
-
self.
|
11
|
+
self.provider_name = "hcloud"
|
12
|
+
|
13
|
+
def setup
|
14
|
+
::HCloud::Client.connection = ::HCloud::Client.new(access_token: key)
|
15
|
+
end
|
10
16
|
|
11
17
|
def ==(other)
|
12
18
|
key == other.key
|
@@ -4,7 +4,52 @@ module Kozo
|
|
4
4
|
module Providers
|
5
5
|
module HCloud
|
6
6
|
class Resource < Kozo::Resource
|
7
|
-
self.
|
7
|
+
self.provider_name = "hcloud"
|
8
|
+
|
9
|
+
attribute :id, type: :integer
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def refresh
|
14
|
+
resource = resource_class.find(id)
|
15
|
+
|
16
|
+
attribute_names
|
17
|
+
.excluding(:id)
|
18
|
+
.each { |attr| send(:"#{attr}=", resource.send(attr)) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def create
|
22
|
+
resource = resource_class.new(**attributes.except(:id))
|
23
|
+
resource.create
|
24
|
+
|
25
|
+
attribute_names
|
26
|
+
.each { |attr| send(:"#{attr}=", resource.send(attr)) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def update
|
30
|
+
resource = resource_class.find(id)
|
31
|
+
|
32
|
+
attribute_names
|
33
|
+
.excluding(:id)
|
34
|
+
.each { |attr| resource.send(:"#{attr}=", send(attr)) }
|
35
|
+
|
36
|
+
resource.update
|
37
|
+
|
38
|
+
attribute_names
|
39
|
+
.excluding(:id)
|
40
|
+
.each { |attr| send(:"#{attr}=", resource.send(attr)) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def destroy
|
44
|
+
resource = resource_class.find(id)
|
45
|
+
resource.delete
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def resource_class
|
51
|
+
"HCloud::#{self.class.name.demodulize}".constantize
|
52
|
+
end
|
8
53
|
end
|
9
54
|
end
|
10
55
|
end
|