Skip to content

Commit

Permalink
Add terraform import command (#244)
Browse files Browse the repository at this point in the history
  • Loading branch information
zzaakiirr authored Dec 1, 2024
1 parent 4233b8b commit d01b5f4
Show file tree
Hide file tree
Showing 31 changed files with 535 additions and 119 deletions.
8 changes: 8 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,14 @@ cpflow setup-app -a $APP_NAME
cpflow terraform generate
```
### `terraform import`
- Imports terraform resources from the generated configuration files
```sh
cpflow terraform import
```
### `version`
- Displays the current version of the CLI
Expand Down
2 changes: 1 addition & 1 deletion lib/command/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def self.all_commands # rubocop:disable Metrics/MethodLength
Dir["#{__dir__}/**/*.rb"].each_with_object({}) do |file, result|
content = File.read(file)

classname = content.match(/^\s+class (\w+) < (?:.*Base)(?:$| .*$)/)&.captures&.first
classname = content.match(/^\s+class (?!Base\b)(\w+) < (?:.*(?!Command::)Base)(?:$| .*$)/)&.captures&.first
next unless classname

namespaces = content.scan(/^\s+module (\w+)/).flatten
Expand Down
35 changes: 35 additions & 0 deletions lib/command/terraform/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# frozen_string_literal: true

module Command
module Terraform
class Base < Command::Base
private

def templates
parser = TemplateParser.new(self)
template_files = Dir["#{parser.template_dir}/*.yml"]

if template_files.empty?
Shell.warn("No templates found in #{parser.template_dir}")
return []
end

parser.parse(template_files)
rescue StandardError => e
Shell.warn("Error parsing templates: #{e.message}")
[]
end

def terraform_dir
@terraform_dir ||= begin
full_path = config.options.fetch(:dir, Cpflow.root_path.join("terraform"))
Pathname.new(full_path).tap do |path|
FileUtils.mkdir_p(path)
rescue StandardError => e
Shell.abort("Invalid directory: #{e.message}")
end
end
end
end
end
end
26 changes: 0 additions & 26 deletions lib/command/terraform/generate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,32 +94,6 @@ def clean_terraform_app_dir(terraform_app_dir)
FileUtils.rm_rf(terraform_app_dir.join(child))
end
end

def templates
parser = TemplateParser.new(self)
template_files = Dir["#{parser.template_dir}/*.yml"]

if template_files.empty?
Shell.warn("No templates found in #{parser.template_dir}")
return []
end

parser.parse(template_files)
rescue StandardError => e
Shell.warn("Error parsing templates: #{e.message}")
[]
end

def terraform_dir
@terraform_dir ||= begin
full_path = config.options.fetch(:dir, Cpflow.root_path.join("terraform"))
Pathname.new(full_path).tap do |path|
FileUtils.mkdir_p(path)
rescue StandardError => e
Shell.abort("Invalid directory: #{e.message}")
end
end
end
end
end
end
79 changes: 79 additions & 0 deletions lib/command/terraform/import.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# frozen_string_literal: true

module Command
module Terraform
class Import < Base
SUBCOMMAND_NAME = "terraform"
NAME = "import"
OPTIONS = [
app_option,
dir_option
].freeze
DESCRIPTION = "Imports terraform resources"
LONG_DESCRIPTION = <<~DESC
- Imports terraform resources from the generated configuration files
DESC
WITH_INFO_HEADER = false

def call
Array(config.app || config.apps.keys).each do |app|
config.instance_variable_set(:@app, app.to_s)

Dir.chdir(terraform_app_dir) do
run_terraform_init

resources.each do |resource|
run_terraform_import(resource[:address], resource[:id])
end
end
end
end

private

def run_terraform_init
result = Shell.cmd("terraform", "init", capture_stderr: true)

if result[:success]
Shell.info(result[:output])
else
Shell.abort("Failed to initialize terraform - #{result[:output]}")
end
end

def run_terraform_import(address, id)
result = Shell.cmd("terraform", "import", address, id, capture_stderr: true)
Shell.info(result[:output])
end

def resources
tf_configs.filter_map do |tf_config|
next unless tf_config.importable?

{ address: tf_config.reference, id: resource_id(tf_config) }
end
end

def tf_configs
templates.flat_map do |template|
TerraformConfig::Generator.new(config: config, template: template).tf_configs.values
end
end

def resource_id(tf_config)
case tf_config
when TerraformConfig::Gvc, TerraformConfig::Policy,
TerraformConfig::Secret, TerraformConfig::Agent,
TerraformConfig::AuditContext
tf_config.name
else
"#{config.app}:#{tf_config.name}"
end
end

def terraform_app_dir
terraform_dir.join(config.app)
end
end
end
end
13 changes: 9 additions & 4 deletions lib/core/shell.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ class << self
attr_reader :tmp_stderr, :verbose
end

def self.shell
@shell ||= Thor::Shell::Color.new
end

def self.use_tmp_stderr
@tmp_stderr = Tempfile.create

Expand All @@ -35,6 +31,10 @@ def self.confirm(message)
shell.yes?("#{message} (y/N)")
end

def self.info(message)
shell.say(message)
end

def self.warn(message)
Kernel.warn(color("WARNING: #{message}", :yellow))
end
Expand Down Expand Up @@ -97,4 +97,9 @@ def self.trap_interrupt
exit(ExitCode::INTERRUPT)
end
end

def self.shell
@shell ||= Thor::Shell::Color.new
end
private_class_method :shell
end
8 changes: 8 additions & 0 deletions lib/core/terraform_config/agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ def initialize(name:, description: nil, tags: nil)
@tags = tags
end

def importable?
true
end

def reference
"cpln_agent.#{name}"
end

def to_tf
block :resource, :cpln_agent, name do
argument :name, name
Expand Down
8 changes: 8 additions & 0 deletions lib/core/terraform_config/audit_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ def initialize(name:, description: nil, tags: nil)
@tags = tags
end

def importable?
true
end

def reference
"cpln_audit_context.#{name}"
end

def to_tf
block :resource, :cpln_audit_context, name do
argument :name, name
Expand Down
8 changes: 8 additions & 0 deletions lib/core/terraform_config/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ module TerraformConfig
class Base
include Dsl

def importable?
false
end

def reference
raise NotImplementedError if importable?
end

def to_tf
raise NotImplementedError
end
Expand Down
8 changes: 8 additions & 0 deletions lib/core/terraform_config/gvc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ def initialize( # rubocop:disable Metrics/ParameterLists
@load_balancer = load_balancer&.deep_underscore_keys&.deep_symbolize_keys
end

def importable?
true
end

def reference
"cpln_gvc.#{name}"
end

def to_tf
block :resource, :cpln_gvc, name do
argument :name, name
Expand Down
8 changes: 8 additions & 0 deletions lib/core/terraform_config/identity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ def initialize(gvc:, name:, description: nil, tags: nil)
@tags = tags
end

def importable?
true
end

def reference
"cpln_identity.#{name}"
end

def to_tf
block :resource, :cpln_identity, name do
argument :gvc, gvc
Expand Down
8 changes: 8 additions & 0 deletions lib/core/terraform_config/policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ def initialize( # rubocop:disable Metrics/ParameterLists, Metrics/MethodLength
@bindings = bindings&.map { |data| data.deep_underscore_keys.deep_symbolize_keys }
end

def importable?
true
end

def reference
"cpln_policy.#{name}"
end

def to_tf
block :resource, :cpln_policy, name do
argument :name, name
Expand Down
8 changes: 8 additions & 0 deletions lib/core/terraform_config/secret.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ def initialize(name:, type:, data:, description: nil, tags: nil)
@data = prepare_data(type: type, data: data)
end

def importable?
true
end

def reference
"cpln_secret.#{name}"
end

def to_tf
block :resource, :cpln_secret, name do
argument :name, name
Expand Down
8 changes: 8 additions & 0 deletions lib/core/terraform_config/volume_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ def initialize( # rubocop:disable Metrics/ParameterLists, Metrics/MethodLength
validate_attributes!
end

def importable?
true
end

def reference
"cpln_volume_set.#{name}"
end

def to_tf
block :resource, :cpln_volume_set, name do
base_arguments_tf
Expand Down
10 changes: 9 additions & 1 deletion lib/core/terraform_config/workload.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

module TerraformConfig
class Workload < Base
class Workload < Base # rubocop:disable Metrics/ClassLength
RAW_ARGS = %i[
containers options local_options rollout_options security_options
firewall_spec load_balancer job
Expand Down Expand Up @@ -64,6 +64,14 @@ def initialize( # rubocop:disable Metrics/ParameterLists, Metrics/MethodLength
@job = job
end

def importable?
true
end

def reference
"module.#{name}.cpln_workload.workload"
end

def to_tf
block :module, name do
argument :source, "../workload"
Expand Down
1 change: 1 addition & 0 deletions lib/cpflow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

# We need to require base before all commands, since the commands inherit from it
require_relative "command/base"
require_relative "command/terraform/base"
# We need to require base terraform config before all commands, since the terraform configs inherit from it
require_relative "core/terraform_config/base"

Expand Down
Loading

0 comments on commit d01b5f4

Please sign in to comment.