terraform-enterprise-cli 0.0.6
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.
- checksums.yaml +7 -0
- data/LICENSE +373 -0
- data/README.md +75 -0
- data/bin/tfe +4 -0
- data/lib/terraform-enterprise-command-line.rb +79 -0
- data/lib/terraform_enterprise/command_line/command.rb +61 -0
- data/lib/terraform_enterprise/command_line/commands/configuration_versions.rb +37 -0
- data/lib/terraform_enterprise/command_line/commands/oauth_tokens.rb +15 -0
- data/lib/terraform_enterprise/command_line/commands/organizations.rb +30 -0
- data/lib/terraform_enterprise/command_line/commands/policies.rb +72 -0
- data/lib/terraform_enterprise/command_line/commands/policy_checks.rb +29 -0
- data/lib/terraform_enterprise/command_line/commands/runs.rb +88 -0
- data/lib/terraform_enterprise/command_line/commands/teams.rb +33 -0
- data/lib/terraform_enterprise/command_line/commands/variables.rb +61 -0
- data/lib/terraform_enterprise/command_line/commands/workspaces.rb +87 -0
- data/lib/terraform_enterprise/command_line/formatter.rb +131 -0
- data/lib/terraform_enterprise/command_line/strings.rb +149 -0
- data/lib/terraform_enterprise/command_line/util.rb +50 -0
- data/lib/terraform_enterprise/command_line/version.rb +5 -0
- metadata +144 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'terraform_enterprise/command_line/command'
|
2
|
+
|
3
|
+
module TerraformEnterprise
|
4
|
+
module CommandLine
|
5
|
+
class VariablesCommand < TerraformEnterprise::CommandLine::Command
|
6
|
+
ATTR_STR = STRINGS[:variables][:attributes]
|
7
|
+
CMD_STR = STRINGS[:variables][:commands]
|
8
|
+
|
9
|
+
desc 'list', CMD_STR[:list]
|
10
|
+
option :table, type: :boolean, default: true, desc: STRINGS[:options][:table]
|
11
|
+
option :organization, required: true, type: :string, desc: ATTR_STR[:organization]
|
12
|
+
option :workspace, type: :string, desc: ATTR_STR[:workspace]
|
13
|
+
def list
|
14
|
+
render client.variables.list(options)
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'create <key> <value>', CMD_STR[:create]
|
18
|
+
option :organization, required: true, type: :string, desc: ATTR_STR[:organization]
|
19
|
+
option :workspace, required: true, type: :string, desc: ATTR_STR[:workspace]
|
20
|
+
option :category, default: 'terraform', type: :string, desc: ATTR_STR[:category], enum:['terraform', 'env']
|
21
|
+
option :hcl, default: false, type: :boolean, desc: ATTR_STR[:hcl]
|
22
|
+
option :sensitive, default: false, type: :boolean, desc: ATTR_STR[:sensitive]
|
23
|
+
def create(key, value)
|
24
|
+
params = {
|
25
|
+
category: options[:category],
|
26
|
+
hcl: options[:hcl],
|
27
|
+
key: key,
|
28
|
+
organization: options[:organization],
|
29
|
+
sensitive: options[:sensitive],
|
30
|
+
value: value,
|
31
|
+
workspace: options[:workspace],
|
32
|
+
}
|
33
|
+
render client.variables.create(params)
|
34
|
+
end
|
35
|
+
|
36
|
+
desc 'update <id>', CMD_STR[:update]
|
37
|
+
option :hcl, type: :boolean, desc: ATTR_STR[:hcl]
|
38
|
+
option :sensitive, type: :boolean, desc: ATTR_STR[:sensitive]
|
39
|
+
option :key, type: :string, desc: ATTR_STR[:key]
|
40
|
+
option :value, type: :string, desc: ATTR_STR[:value]
|
41
|
+
def update(id)
|
42
|
+
params = {id: id}
|
43
|
+
params[:hcl] = options[:hcl] if options.include?('hcl')
|
44
|
+
params[:key] = options[:key] if options[:key]
|
45
|
+
params[:sensitive] = options[:sensitive] if options.include?('sensitive')
|
46
|
+
params[:value] = options[:value] if options[:value]
|
47
|
+
render client.variables.update(params)
|
48
|
+
end
|
49
|
+
|
50
|
+
desc 'get <id>', CMD_STR[:get]
|
51
|
+
def get(id)
|
52
|
+
render client.variables.get(id:id)
|
53
|
+
end
|
54
|
+
|
55
|
+
desc 'delete <id>', CMD_STR[:delete]
|
56
|
+
def delete(id)
|
57
|
+
render client.variables.delete(id: id)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'terraform_enterprise/command_line/command'
|
2
|
+
|
3
|
+
module TerraformEnterprise
|
4
|
+
module CommandLine
|
5
|
+
class WorkspacesCommand < TerraformEnterprise::CommandLine::Command
|
6
|
+
ATTR_STR = STRINGS[:workspaces][:attributes]
|
7
|
+
CMD_STR = STRINGS[:workspaces][:commands]
|
8
|
+
|
9
|
+
desc 'list', CMD_STR[:list]
|
10
|
+
option :organization, required: true, type: :string, desc: ATTR_STR[:organization]
|
11
|
+
option :table, type: :boolean, default: true, desc: STRINGS[:options][:table]
|
12
|
+
def list
|
13
|
+
render client.workspaces.list(options), except:[:permissions, :actions, :environment, 'created-at']
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'create <name>', CMD_STR[:create]
|
17
|
+
option :terraform_version, type: :string, desc: ATTR_STR[:terraform_version]
|
18
|
+
option :working_directory, type: :string, desc: ATTR_STR[:working_directory]
|
19
|
+
option :oauth_token, type: :string, desc: ATTR_STR[:oauth_token]
|
20
|
+
option :branch, type: :string, desc: ATTR_STR[:branch]
|
21
|
+
option :ingress_submodules, type: :boolean, desc: ATTR_STR[:ingress_submodules]
|
22
|
+
option :repo, type: :string, desc: ATTR_STR[:repos]
|
23
|
+
option :import_legacy_environment, type: :string, desc: ATTR_STR[:import_legacy]
|
24
|
+
option :organization, required: true, type: :string, desc: ATTR_STR[:organization]
|
25
|
+
def create(name)
|
26
|
+
params = {
|
27
|
+
organization: options[:organization],
|
28
|
+
name: name,
|
29
|
+
'working-directory' => options[:working_directory] || '',
|
30
|
+
}
|
31
|
+
if options[:repo] && options[:oauth_token]
|
32
|
+
repo = {}
|
33
|
+
repo['branch'] = options[:branch] || ''
|
34
|
+
repo['identifier'] = options[:repo]
|
35
|
+
repo['oauth-token-id'] = options[:oauth_token]
|
36
|
+
repo['ingress-submodules'] = options[:ingress_submodules] || false
|
37
|
+
params['vcs-repo'] = repo
|
38
|
+
end
|
39
|
+
|
40
|
+
params['migration-environment'] = options[:import_legacy_environment] if options[:import_legacy_environment]
|
41
|
+
params['terraform_version'] = options[:terraform_version] if options[:terraform_version]
|
42
|
+
render client.workspaces.create(params), except:[:permissions, :actions, :environment]
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'get <name>', CMD_STR[:get]
|
46
|
+
option :organization, required: true, type: :string, desc: ATTR_STR[:organization]
|
47
|
+
def get(name)
|
48
|
+
params = {
|
49
|
+
organization: options[:organization],
|
50
|
+
workspace: name
|
51
|
+
}
|
52
|
+
render client.workspaces.get(params), except:[:permissions, :environment]
|
53
|
+
end
|
54
|
+
|
55
|
+
desc 'delete <name>', CMD_STR[:delete]
|
56
|
+
option :organization, required: true, type: :string, desc: ATTR_STR[:organization]
|
57
|
+
def delete(name)
|
58
|
+
params = {
|
59
|
+
organization: options[:organization],
|
60
|
+
workspace: name
|
61
|
+
}
|
62
|
+
render client.workspaces.delete(params), except:[:permissions, :actions, :environment]
|
63
|
+
end
|
64
|
+
|
65
|
+
desc 'update <name>', CMD_STR[:update]
|
66
|
+
option :working_directory, type: :string, desc: ATTR_STR[:working_directory]
|
67
|
+
option :terraform_version, type: :string, desc: ATTR_STR[:terraform_version]
|
68
|
+
option :auto_apply, type: :boolean, desc: ATTR_STR[:auto_apply]
|
69
|
+
option :organization, required: true, type: :string, desc: ATTR_STR[:organization]
|
70
|
+
def update(name)
|
71
|
+
params = options
|
72
|
+
params[:workspace] = name
|
73
|
+
render client.workspaces.update(params), except:[:permissions, :environment]
|
74
|
+
end
|
75
|
+
|
76
|
+
desc 'lock <id>', CMD_STR[:lock]
|
77
|
+
def lock(id)
|
78
|
+
render client.workspaces.action(action: :lock, id: id), except:[:permissions, :environment]
|
79
|
+
end
|
80
|
+
|
81
|
+
desc 'unlock <id>', CMD_STR[:unlock]
|
82
|
+
def unlock(id)
|
83
|
+
render client.workspaces.action(action: :unlock, id: id), except:[:permissions, :environment]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'colorize'
|
3
|
+
require 'terminal-table'
|
4
|
+
|
5
|
+
require 'terraform-enterprise-client'
|
6
|
+
|
7
|
+
module TerraformEnterprise
|
8
|
+
module CommandLine
|
9
|
+
# Module with render method to render the Resource object
|
10
|
+
class Formatter
|
11
|
+
def render(obj, options = {})
|
12
|
+
String.disable_colorization = !options[:color]
|
13
|
+
|
14
|
+
if !obj.is_a?(TerraformEnterprise::API::Response)
|
15
|
+
unkown_response(obj)
|
16
|
+
elsif obj.success?
|
17
|
+
render_resource(obj, options)
|
18
|
+
elsif obj.errors?
|
19
|
+
render_errors(obj)
|
20
|
+
else
|
21
|
+
unkown_response(obj.body)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def error(message)
|
26
|
+
puts "Error: #{message}".red
|
27
|
+
end
|
28
|
+
|
29
|
+
def success(message)
|
30
|
+
puts message.green
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def unkown_response(obj)
|
36
|
+
puts 'Unknown response'.yellow
|
37
|
+
puts obj
|
38
|
+
exit(false)
|
39
|
+
end
|
40
|
+
|
41
|
+
def render_resource(obj, options)
|
42
|
+
if obj.resources
|
43
|
+
puts render_resource_list(obj.resources, options)
|
44
|
+
elsif obj.resource
|
45
|
+
puts render_resource_item(obj.resource, options)
|
46
|
+
else
|
47
|
+
success "Success (#{obj.code})"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def render_errors(obj)
|
52
|
+
obj.errors.each do |error|
|
53
|
+
message = error['detail'] || error['title'] || error.to_s
|
54
|
+
code = error['status'] || obj.code
|
55
|
+
error "[#{code}] #{message}"
|
56
|
+
end
|
57
|
+
exit(false)
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_resource(resource, options)
|
61
|
+
parsed_resource = flatten_dotted_hash(resource.attributes)
|
62
|
+
if resource.id
|
63
|
+
parsed_resource = { 'id' => resource.id }.merge(parsed_resource)
|
64
|
+
end
|
65
|
+
(options[:except] || []).each do |excluded|
|
66
|
+
parsed_resource.delete_if do |key, _|
|
67
|
+
key.to_s.start_with?(excluded.to_s)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
if options[:only] && !options[:only].empty?
|
71
|
+
parsed_resource.select! do |key, _|
|
72
|
+
options[:only].any? do |included|
|
73
|
+
key.to_s.start_with?(included.to_s)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
parsed_resource
|
78
|
+
end
|
79
|
+
|
80
|
+
def render_resource_item(resource, options)
|
81
|
+
parsed_resource = parse_resource(resource, options)
|
82
|
+
parsed_resource.keys.map do |key|
|
83
|
+
value = parsed_resource[key]
|
84
|
+
options[:value] ? value : "#{key.bold}: #{value}"
|
85
|
+
end.join("\n")
|
86
|
+
end
|
87
|
+
|
88
|
+
def render_resource_list(resources, options)
|
89
|
+
if options[:table] && !options[:value]
|
90
|
+
parsed_resources = resources.map do |resource|
|
91
|
+
parse_resource(resource, options)
|
92
|
+
end
|
93
|
+
keys = parsed_resources.map(&:keys).flatten.uniq
|
94
|
+
rows = parsed_resources.map do |resource|
|
95
|
+
keys.map { |key| resource[key] }
|
96
|
+
end
|
97
|
+
table = Terminal::Table.new headings: keys, rows: rows
|
98
|
+
table
|
99
|
+
else
|
100
|
+
line_separator = "\n#{'-' * 10}\n"
|
101
|
+
out = resources.map do |resource|
|
102
|
+
render_resource_item(resource, options)
|
103
|
+
end
|
104
|
+
out.join(line_separator)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def flatten_hash(hash, new_key = [], new_hash = {})
|
109
|
+
if hash.is_a?(Array)
|
110
|
+
hash.each_with_index do |item, obj|
|
111
|
+
flatten_hash(item, new_key + [obj], new_hash)
|
112
|
+
end
|
113
|
+
elsif hash.is_a?(Hash)
|
114
|
+
hash.each do |key, value|
|
115
|
+
flatten_hash(value, new_key + [key], new_hash)
|
116
|
+
end
|
117
|
+
else
|
118
|
+
return new_hash.update(new_key => hash)
|
119
|
+
end
|
120
|
+
new_hash
|
121
|
+
end
|
122
|
+
|
123
|
+
def flatten_dotted_hash(source)
|
124
|
+
flat = flatten_hash(source)
|
125
|
+
flat.keys.each_with_object({}) do |key, h|
|
126
|
+
h[key.join('.')] = flat[key]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module TerraformEnterprise
|
4
|
+
module CommandLine
|
5
|
+
STRINGS = {
|
6
|
+
options: {
|
7
|
+
table: 'Format list output as a table',
|
8
|
+
host: 'Set host address for private Terraform Enterprise',
|
9
|
+
token: 'Set the auth token, defaults to TFE_TOKEN environment variable',
|
10
|
+
color: 'If disabled the ANSI color codes will not be used',
|
11
|
+
except: 'List of fields that should not be displayed',
|
12
|
+
only: 'List of fields that should be displayed',
|
13
|
+
all: 'Return all fields, not just summary',
|
14
|
+
value: 'Only return the value; i.e. do not show keys',
|
15
|
+
debug: 'Show debug logs'
|
16
|
+
},
|
17
|
+
push: {
|
18
|
+
attributes: {
|
19
|
+
path: 'Path of directory or tar.gz file to push to the workspace'
|
20
|
+
},
|
21
|
+
commands: {
|
22
|
+
push: 'Pushes the configuration to the workspace'
|
23
|
+
}
|
24
|
+
},
|
25
|
+
workspaces: {
|
26
|
+
attributes: {
|
27
|
+
terraform_version: 'Version of Terraform to use for this workspace.',
|
28
|
+
working_directory: 'Relative path that Terraform will execute within.',
|
29
|
+
oauth_token: 'VCS Connection (OAuth Conection + Token) to use as identified; obtained from the oauth_tokens subcommand.',
|
30
|
+
branch: 'Repository branch that Terraform will execute from.',
|
31
|
+
ingress_submodules: 'Submodules should be fetched when cloning the VCS repository.',
|
32
|
+
repo: 'Reference to VCS repository in the format :org/:repo.',
|
33
|
+
import_legacy: 'Specifies the legacy Environment to use as the source of the migration/',
|
34
|
+
organization: 'Organization to which this workspaces belongs to.',
|
35
|
+
auto_apply: 'Auto-apply enabled'
|
36
|
+
},
|
37
|
+
commands: {
|
38
|
+
create: 'Create a new workspace',
|
39
|
+
list: 'List workspaces in the organization',
|
40
|
+
get: 'Get workspace details by name',
|
41
|
+
delete: 'Delete the workspace',
|
42
|
+
update: 'Update the workspace',
|
43
|
+
lock: 'Lock the workspace by workspace ID',
|
44
|
+
unlock: 'Unlock the workspace by workspace ID'
|
45
|
+
}
|
46
|
+
},
|
47
|
+
configuration_versions: {
|
48
|
+
attributes: {
|
49
|
+
workspace_id: 'Workspace ID of the workspace to which the configuration version belongs to.',
|
50
|
+
path: 'Path to the tar.gz file'
|
51
|
+
},
|
52
|
+
commands: {
|
53
|
+
create: 'Create a new configuration version',
|
54
|
+
list: 'List configuration versions in the organization',
|
55
|
+
get: 'Get configuration version details by name',
|
56
|
+
upload: 'Upload a file to the configuration version'
|
57
|
+
}
|
58
|
+
},
|
59
|
+
organizations: {
|
60
|
+
commands: {
|
61
|
+
create: 'Create a new organization',
|
62
|
+
list: 'List all the organizations',
|
63
|
+
get: 'Get organization details by name',
|
64
|
+
delete: 'Delete the organization'
|
65
|
+
},
|
66
|
+
attributes: {}
|
67
|
+
},
|
68
|
+
teams: {
|
69
|
+
commands: {
|
70
|
+
create: 'Create a new team',
|
71
|
+
delete: 'Delete the team by ID',
|
72
|
+
list: 'List teams in organization',
|
73
|
+
get: 'Get team details'
|
74
|
+
},
|
75
|
+
attributes: {
|
76
|
+
organization: 'Organization to which this Team belongs to.'
|
77
|
+
}
|
78
|
+
},
|
79
|
+
policies: {
|
80
|
+
commands: {
|
81
|
+
create: 'Create a new policy',
|
82
|
+
delete: 'Delete a policy by ID',
|
83
|
+
list: 'List policies in organization',
|
84
|
+
get: 'Get policy details',
|
85
|
+
upload: 'Upload a policy'
|
86
|
+
},
|
87
|
+
attributes: {
|
88
|
+
organization: 'Organization to which this Team belongs to.',
|
89
|
+
mode: 'Policy mode, hard-mandatory, soft-mandatory or advisory',
|
90
|
+
name: 'Policy name'
|
91
|
+
}
|
92
|
+
},
|
93
|
+
runs: {
|
94
|
+
commands: {
|
95
|
+
create: 'Create a new run',
|
96
|
+
list: 'List runs in a workspace',
|
97
|
+
get: 'Get run details',
|
98
|
+
apply: 'Apply the plan',
|
99
|
+
discard: 'Discard the plan',
|
100
|
+
log: 'Return logs for the plan or apply'
|
101
|
+
},
|
102
|
+
attributes: {
|
103
|
+
workspace_id: 'Workspace ID of which the run belongs to.',
|
104
|
+
configuration_version_id: 'Configuration Version ID of the configuration version to run',
|
105
|
+
destroy: 'The run should be a destroy plan',
|
106
|
+
comment: 'Add a comment for the action',
|
107
|
+
follow: 'Follow the logs until output is complete',
|
108
|
+
event: 'Run event for which to get logs (plan or apply)'
|
109
|
+
}
|
110
|
+
},
|
111
|
+
policy_checks: {
|
112
|
+
commands: {
|
113
|
+
list: 'List policy checks on run',
|
114
|
+
override: 'Override the soft-mandatory or advisory policy'
|
115
|
+
},
|
116
|
+
attributes: {
|
117
|
+
run_id: 'Run ID to which the policy check belongs to.',
|
118
|
+
comment: 'Add a comment for the action'
|
119
|
+
}
|
120
|
+
},
|
121
|
+
oauth_tokens: {
|
122
|
+
commands: {
|
123
|
+
list: 'List the OAuth tokens in the organization'
|
124
|
+
},
|
125
|
+
attributes: {
|
126
|
+
organization: 'Organization to which this OAuth Token belongs to.'
|
127
|
+
}
|
128
|
+
},
|
129
|
+
variables: {
|
130
|
+
commands: {
|
131
|
+
create: 'Create a new variable',
|
132
|
+
delete: 'Delete the variable by ID',
|
133
|
+
get: 'Get variable details',
|
134
|
+
list: 'List variables in organization',
|
135
|
+
update: 'Update a variable by ID'
|
136
|
+
},
|
137
|
+
attributes: {
|
138
|
+
organization: 'Organization to which this Variable belongs to.',
|
139
|
+
workspace: 'Workspace to which this Variable belongs to.',
|
140
|
+
category: 'The type of category, probably "terraform" or "env"',
|
141
|
+
hcl: 'Variable should be parsed using HCL',
|
142
|
+
sensitive: 'Variable should be marked as sensitive',
|
143
|
+
value: 'Variable value',
|
144
|
+
key: 'Variable key'
|
145
|
+
}
|
146
|
+
}
|
147
|
+
}.freeze
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rubygems/package'
|
2
|
+
require 'zlib'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module TerraformEnterprise
|
6
|
+
module CommandLine
|
7
|
+
module Util
|
8
|
+
# Module to perform a tar and gz of a directory
|
9
|
+
module Tar
|
10
|
+
def tar(path)
|
11
|
+
tarfile = StringIO.new('')
|
12
|
+
Gem::Package::TarWriter.new(tarfile) do |tar|
|
13
|
+
Dir[File.join(path, '**/*')].each do |file|
|
14
|
+
mode = File.stat(file).mode
|
15
|
+
relative_file = file.sub /^#{Regexp.escape(path)}\/?/, ''
|
16
|
+
|
17
|
+
if File.directory?(file)
|
18
|
+
tar.mkdir relative_file, mode
|
19
|
+
else
|
20
|
+
tar.add_file relative_file, mode do |tf|
|
21
|
+
File.open(file, 'rb') { |f| tf.write f.read }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
tarfile.rewind
|
28
|
+
tarfile
|
29
|
+
end
|
30
|
+
|
31
|
+
def gzip(tarfile)
|
32
|
+
gzip_string = StringIO.new('')
|
33
|
+
gzip_writer = Zlib::GzipWriter.new(gzip_string)
|
34
|
+
gzip_writer.write tarfile.string
|
35
|
+
gzip_writer.close
|
36
|
+
gzip_string.string
|
37
|
+
end
|
38
|
+
|
39
|
+
def tarball(path)
|
40
|
+
full_path = File.expand_path(path)
|
41
|
+
if File.directory?(full_path)
|
42
|
+
gzip(tar(full_path))
|
43
|
+
else
|
44
|
+
File.read(full_path)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|