unimatrix-cli 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/README.md +12 -0
  6. data/Rakefile +6 -0
  7. data/VERSION +1 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +8 -0
  10. data/exe/unimatrix +11 -0
  11. data/lib/unimatrix_cli.rb +74 -0
  12. data/lib/unimatrix_cli/alchemist/rendition/list_command.rb +72 -0
  13. data/lib/unimatrix_cli/alchemist/rendition_profile/assign_command.rb +59 -0
  14. data/lib/unimatrix_cli/alchemist/rendition_profile/list_command.rb +36 -0
  15. data/lib/unimatrix_cli/alchemist/video/create_command.rb +40 -0
  16. data/lib/unimatrix_cli/alchemist/video/describe_command.rb +40 -0
  17. data/lib/unimatrix_cli/alchemist/video_encoder/create_command.rb +37 -0
  18. data/lib/unimatrix_cli/alchemist/video_encoder/describe_command.rb +39 -0
  19. data/lib/unimatrix_cli/alchemist/video_encoder/encode_command.rb +102 -0
  20. data/lib/unimatrix_cli/alchemist/video_encoder/list_command.rb +35 -0
  21. data/lib/unimatrix_cli/archivist/blueprint/create_command.rb +94 -0
  22. data/lib/unimatrix_cli/citadel/app/build_command.rb +28 -0
  23. data/lib/unimatrix_cli/citadel/app/console_command.rb +17 -0
  24. data/lib/unimatrix_cli/citadel/app/db_setup_command.rb +17 -0
  25. data/lib/unimatrix_cli/citadel/app/environment_command.rb +30 -0
  26. data/lib/unimatrix_cli/citadel/app/logs_command.rb +17 -0
  27. data/lib/unimatrix_cli/citadel/app/migrate_command.rb +17 -0
  28. data/lib/unimatrix_cli/citadel/app/migrate_status_command.rb +17 -0
  29. data/lib/unimatrix_cli/citadel/app/rake_command.rb +18 -0
  30. data/lib/unimatrix_cli/citadel/app/routes_command.rb +17 -0
  31. data/lib/unimatrix_cli/citadel/citadel_command.rb +285 -0
  32. data/lib/unimatrix_cli/citadel/instance/details_command.rb +18 -0
  33. data/lib/unimatrix_cli/citadel/instance/scp_command.rb +48 -0
  34. data/lib/unimatrix_cli/citadel/instance/ssh_command.rb +29 -0
  35. data/lib/unimatrix_cli/citadel/instance/status_command.rb +17 -0
  36. data/lib/unimatrix_cli/citadel/instance/user_data_command.rb +17 -0
  37. data/lib/unimatrix_cli/citadel/instance/user_data_logs_command.rb +17 -0
  38. data/lib/unimatrix_cli/cli.rb +30 -0
  39. data/lib/unimatrix_cli/command.rb +138 -0
  40. data/lib/unimatrix_cli/config/acceptance.yml +23 -0
  41. data/lib/unimatrix_cli/config/configuration.rb +66 -0
  42. data/lib/unimatrix_cli/config/production.yml +15 -0
  43. data/lib/unimatrix_cli/config/staging.yml +15 -0
  44. data/lib/unimatrix_cli/config/unimatrix.rb +4 -0
  45. data/lib/unimatrix_cli/iris/stream/create_command.rb +43 -0
  46. data/lib/unimatrix_cli/iris/stream/describe_command.rb +35 -0
  47. data/lib/unimatrix_cli/iris/stream_encoder/create_command.rb +43 -0
  48. data/lib/unimatrix_cli/iris/stream_encoder/describe_command.rb +37 -0
  49. data/lib/unimatrix_cli/iris/stream_input/create_command.rb +43 -0
  50. data/lib/unimatrix_cli/iris/stream_input/describe_command.rb +37 -0
  51. data/lib/unimatrix_cli/iris/stream_output/create_command.rb +55 -0
  52. data/lib/unimatrix_cli/iris/stream_output/describe_command.rb +37 -0
  53. data/lib/unimatrix_cli/iris/stream_recorder/create_command.rb +49 -0
  54. data/lib/unimatrix_cli/iris/stream_recorder/describe_command.rb +37 -0
  55. data/lib/unimatrix_cli/iris/stream_transcriber/create_command.rb +54 -0
  56. data/lib/unimatrix_cli/iris/stream_transcriber/describe_command.rb +37 -0
  57. data/lib/unimatrix_cli/iris/stream_transmutator/create_command.rb +65 -0
  58. data/lib/unimatrix_cli/iris/stream_transmutator/describe_command.rb +38 -0
  59. data/lib/unimatrix_cli/login_command.rb +91 -0
  60. data/lib/unimatrix_cli/logout_command.rb +21 -0
  61. data/lib/unimatrix_cli/version.rb +3 -0
  62. data/lib/unimatrix_cli/zephyrus/input/create_command.rb +40 -0
  63. data/lib/unimatrix_cli/zephyrus/input/describe_command.rb +35 -0
  64. data/lib/unimatrix_cli/zephyrus/input/list_command.rb +38 -0
  65. data/lib/unimatrix_cli/zephyrus/output/list_command.rb +44 -0
  66. data/lib/unimatrix_cli/zephyrus/recording/configuration_command.rb +43 -0
  67. data/lib/unimatrix_cli/zephyrus/rendition/list_command.rb +40 -0
  68. data/lib/unimatrix_cli/zephyrus/routing/configuration_command.rb +43 -0
  69. data/lib/unimatrix_cli/zephyrus/transcoding/configuration_command.rb +55 -0
  70. data/lib/unimatrix_cli/zephyrus/transcribing/configuration_command.rb +55 -0
  71. data/lib/unimatrix_cli/zephyrus/transmutation/configuration_command.rb +55 -0
  72. data/lib/unimatrix_parser.rb +796 -0
  73. data/unimatrix-cli.gemspec +30 -0
  74. metadata +247 -0
@@ -0,0 +1,17 @@
1
+ module UnimatrixCLI
2
+ module Citadel
3
+ module App
4
+ class RoutesCommand < CitadelCommand
5
+
6
+ option :app, "Keyword for the name of the app", type: :string, required: true
7
+
8
+ synopsis "Display rails routes on a Rails-based API instance"
9
+
10
+ def execute
11
+ super
12
+ execute_command( 'routes' )
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,285 @@
1
+ require 'tty-prompt'
2
+ require 'aws-sdk'
3
+ require 'net/ssh'
4
+
5
+ module UnimatrixCLI
6
+ module Citadel
7
+ class CitadelCommand < Command
8
+
9
+ APIS = %w( activist alchemist analyst anemoi archivist
10
+ cartographer curator distributor dealer fabricator iris
11
+ keymaker merchant organizer portal regent universal zephyrus )
12
+
13
+ ROOT = %w( status bastion efsm environment user_data_logs )
14
+
15
+ PRIVATE_SUBNETS = %w( subnet-6788a72c subnet-761b7a59 subnet-71340a38
16
+ subnet-db541df6 subnet-699ce444 subnet-dbeeddf6
17
+ subnet-cf507986 subnet-7cedde51 subnet-5e505816 )
18
+
19
+ def execute
20
+ if load_environment && instance_list
21
+ write_instance_details( instance_details[ :instance_id ] )
22
+ end
23
+ end
24
+
25
+ def load_environment
26
+ Dotenv.load if defined?( Dotenv )
27
+ if ENV[ 'AWS_REGION' ] &&
28
+ ENV[ 'server_key' ] &&
29
+ ENV[ 'AWS_ACCESS_KEY_ID' ] &&
30
+ ENV[ 'AWS_SECRET_ACCESS_KEY' ]
31
+
32
+ Aws.config.update({
33
+ region: ENV[ 'AWS_REGION' ],
34
+ credentials: Aws::Credentials.new(
35
+ ENV[ 'AWS_ACCESS_KEY_ID' ],
36
+ ENV[ 'AWS_SECRET_ACCESS_KEY' ]
37
+ )
38
+ })
39
+ else
40
+ write( message: 'AWS credentials not found', error: true )
41
+ false
42
+ end
43
+ end
44
+
45
+ #----------------------------------------------------------------------------
46
+ # Memoized Variables
47
+
48
+ def instance_list
49
+ @instance_list ||= begin
50
+ app_keyword = @options[ :builder ] || @options[ :app ] || @options[ :instance ]
51
+ instance_list = instances( app_keyword )
52
+
53
+ if instance_list
54
+ instance_list
55
+ else
56
+ write( message: 'Instances not found', error: true )
57
+ false
58
+ end
59
+ end
60
+ end
61
+
62
+ def aws_client
63
+ @aws_client ||= Aws::EC2::Client.new
64
+ end
65
+
66
+ def instance_details
67
+ @instance_details ||= begin
68
+ names = instance_list.map { | instance | instance.keys }.flatten
69
+ chosen_instance = names.length == 1 ? names.first : menu( names )
70
+ collect_instance_details( chosen_instance )
71
+ end
72
+ end
73
+
74
+ def instances_by_zone
75
+ @instances_by_zone ||= begin
76
+ app_keyword = @options[ :builder ] || @options[ :app ] || @options[ :instance ]
77
+ find_instances_by_zone( app_keyword )
78
+ end
79
+ end
80
+
81
+ def user
82
+ @user ||= begin
83
+ sub_command = self.class.to_s.split( '::' ).last.slice( 0...-7 ).downcase
84
+ if ROOT.include?( @options[ :user ] ) ||
85
+ ROOT.include?( sub_command ) ||
86
+ ROOT.include?( instance_details[ :tag ].split( '-' ).first ) ||
87
+ ROOT.include?( instance_details[ :tag ].split( '.' ).first ) ||
88
+ instance_details[ :tag ].include?( 'bastion' ) ||
89
+ instance_details[ :tag ].include?( 'efsm' )
90
+ 'root'
91
+ elsif instance_details[ :tag ].include?( 'worker' )
92
+ 'worker'
93
+ elsif instance_details[ :tag ].include?( 'build' )
94
+ 'ec2-user'
95
+ elsif APIS.include?(
96
+ instance_details[ :tag ].split( '-' ).first
97
+ )
98
+ 'httpd'
99
+ else
100
+ instance_details[ :tag ].split( '-' ).first
101
+ end
102
+ end
103
+ end
104
+
105
+ def key
106
+ @key ||= File.join( '~/.ssh/', ENV[ 'server_key' ] )
107
+ end
108
+
109
+ def account
110
+ @account ||= begin
111
+ id = aws_client.describe_instances.reservations.first[ :owner_id ]
112
+ id == '561599644983' ? account = 'production' : account = 'development'
113
+ end
114
+ end
115
+
116
+ #----------------------------------------------------------------------------
117
+ # Instance Details
118
+
119
+ def write_instance_details( instance_id, options = {} )
120
+ instance = aws_client.describe_instances(
121
+ filters:[ { name: 'instance-id', values: [ instance_id ] } ]
122
+ ).first.to_h[ :reservations ].first[ :instances ].first
123
+
124
+ message = "Name: #{ instance[ :tags ].first[ :value ] }\n" +
125
+ "Instance ID: #{ instance[ :instance_id ] }\n" +
126
+ "Public DNS: #{ instance[ :public_dns_name ] }\n"
127
+
128
+ if options[ :full ]
129
+ message += "Launch Time: #{ instance[ :launch_time ] }\n" +
130
+ "Instance Type: #{ instance[ :instance_type ] }\n"
131
+
132
+ if instance[ :iam_instance_profile ]
133
+ message += "Instance Profile: " +
134
+ "#{ instance[ :iam_instance_profile ][ :arn ] }"
135
+ end
136
+ end
137
+
138
+ write( message: message )
139
+ end
140
+
141
+ private; def instances( app_keyword )
142
+ available_instances = find_instances_by_zone( app_keyword ).flatten.map do | instance |
143
+ if instance[ :state ][ :name ] == 'running'
144
+ { instance[ :tags ].find { | item | item[ :key ] == 'Name' }[ :value ] +
145
+ ' ' + '(' + instance[ :instance_id ] +
146
+ ')' => instance[ :public_dns_name ]
147
+ }
148
+ end
149
+ end
150
+ if available_instances.empty? ||
151
+ ( available_instances.include?( nil ) && available_instances.count == 1 )
152
+ false
153
+ else
154
+ available_instances.compact
155
+ end
156
+ end
157
+
158
+ private; def find_instances_by_zone( app_keyword )
159
+ descriptions = aws_client.describe_instances(
160
+ filters:[ { name: 'tag:Name', values: [ "*#{ app_keyword }*" ] } ]
161
+ ).to_h
162
+
163
+ instances_hash = descriptions.map { | hash | hash[ 1 ] }.first
164
+ instances_by_zone = instances_hash.map do | instances |
165
+ instances[ :instances ]
166
+ end.flatten
167
+ end
168
+
169
+ private; def menu( names )
170
+ prompt = TTY::Prompt.new(
171
+ interrupt: :exit, help_color: :magenta, prefix: 'Citadel:'
172
+ )
173
+ prompt.select( 'Select?', names, active_color: :cyan )
174
+ end
175
+
176
+ private; def development_vpc( vpc )
177
+ vpc == 'vpc-009eb264' ? environment = 'acceptance' : environment = 'staging'
178
+ end
179
+
180
+ private; def collect_instance_details( chosen_instance )
181
+ dns = instance_list.reduce(
182
+ Hash.new, :merge
183
+ ).select { | key, value | key == chosen_instance }[ chosen_instance ]
184
+
185
+ instance_id = chosen_instance.split( ' ' )[ -1 ].gsub( /[()]/, "" )
186
+ tag = chosen_instance.split( ' ' ).first
187
+
188
+ subnet_hash = instances_by_zone.map do | instance |
189
+ if instance[ :state ][ :name ] == 'running'
190
+ { instance[ :instance_id ] => instance[ :subnet_id ] }
191
+ end
192
+ end
193
+
194
+ subnets = subnet_hash.compact.reduce( Hash.new, :merge )
195
+ chosen_subnet = subnets[ instance_id ]
196
+
197
+ concealed = PRIVATE_SUBNETS.any? do | private_subnet |
198
+ chosen_subnet.include?( private_subnet )
199
+ end
200
+
201
+ vpc_hash = instances_by_zone.map do | instance |
202
+ if instance[ :state ][ :name ] == 'running'
203
+ { instance[ :instance_id ] => instance[ :vpc_id ] }
204
+ end
205
+ end
206
+
207
+ vpcs = vpc_hash.compact.reduce( Hash.new, :merge )
208
+
209
+ if account == 'development'
210
+ development_environment = development_vpc( vpcs[ instance_id ] )
211
+ bastion_hash = instances(
212
+ "bastion.#{ development_environment }.#{ ENV[ 'AWS_REGION' ] }"
213
+ )
214
+ else
215
+ bastion_hash = instances( "bastion.#{ ENV[ 'AWS_REGION' ] }" )
216
+ end
217
+
218
+ bastion_dns = bastion_hash.reduce( Hash.new, :merge ).values.first
219
+
220
+ {
221
+ bastion_dns: bastion_dns,
222
+ dns: dns,
223
+ tag: tag,
224
+ instance_id: instance_id,
225
+ account: account,
226
+ concealed: concealed
227
+ }
228
+ end
229
+
230
+ #----------------------------------------------------------------------------
231
+ # Command Execution
232
+
233
+ def execute_command( remote_command )
234
+ command = base_command +
235
+ " -t commands #{ remote_command }"
236
+ command += " #{ @options[ :commands ] }" if @options[ :commands ]
237
+ exec command
238
+ end
239
+
240
+ private; def base_command
241
+ base = "ssh -o StrictHostKeyChecking=no -i #{ key } "
242
+
243
+ if instance_details[ :bastion_dns ] == instance_details[ :dns ] ||
244
+ instance_details[ :tag ] == 'efsm'
245
+
246
+ base += "root@#{ instance_details[ :dns ] }"
247
+
248
+ elsif instance_details[ :account ] == 'production' ||
249
+ instance_details[ :concealed ]
250
+
251
+ base += "root@#{ instance_details[ :bastion_dns ] }"
252
+
253
+ else
254
+ user_to_use = @options[ :user ] || user
255
+ base += "#{ user_to_use }@#{ instance_details[ :dns ] }"
256
+ end
257
+ end
258
+
259
+ def execute_tunnel( remote_command )
260
+ write(
261
+ message: 'Running Via SSH Tunnel. ' +
262
+ 'This command could take a while; please be patient.'
263
+ )
264
+ if instance_details[ :account ] == 'production' ||
265
+ instance_details[ :concealed ]
266
+
267
+ user_to_use = 'root'
268
+ dns_to_use = instance_details[ :bastion_dns ]
269
+ to_exec = "/home/root/scripts/intraface " +
270
+ "#{ instance_details[ :instance_id ] } root" +
271
+ "-t -t #{ remote_command }"
272
+ else
273
+ user_to_use = user
274
+ dns_to_use = instance_details[ :dns ]
275
+ to_exec = "#{ remote_command }"
276
+ end
277
+
278
+ Net::SSH.start( dns_to_use, user_to_use, keys: [ key ] ) do | ssh |
279
+ output = ssh.exec!( to_exec )
280
+ write( message: output )
281
+ end
282
+ end
283
+ end
284
+ end
285
+ end
@@ -0,0 +1,18 @@
1
+ module UnimatrixCLI
2
+ module Citadel
3
+ module Instance
4
+ class DetailsCommand < CitadelCommand
5
+
6
+ option :instance, "Keyword for the name of the instance", type: :string, required: :true
7
+
8
+ synopsis "Display full details for the specified instance"
9
+
10
+ def execute
11
+ if load_environment && instance_list
12
+ write_instance_details( instance_details[ :instance_id ], full: true )
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,48 @@
1
+ module UnimatrixCLI
2
+ module Citadel
3
+ module Instance
4
+ class ScpCommand < CitadelCommand
5
+
6
+ option :instance, "The instance to copy a file from or to", type: :string, required: true
7
+ option :local_file, "The local path and filename", type: :string, required: true
8
+ option :remote_file, "The remote path and filename", type: :string, required: true
9
+ option :direction, "Copy from or to an instance", type: :string, required: true
10
+ option :user, "Connect as a different user (optional)", type: :string
11
+
12
+ synopsis "Copy a file from or to a specific instance"
13
+
14
+ DIRECTIONS = %w( from to )
15
+
16
+ def execute
17
+ if @options[ :direction ] &&
18
+ DIRECTIONS.include?( @options[ :direction ] )
19
+ super
20
+ execute_scp
21
+ else
22
+ write(
23
+ message: "#{ @options[ :direction ] } is not a valid direction",
24
+ error: true
25
+ )
26
+ end
27
+ end
28
+
29
+ #----------------------------------------------------------------------------
30
+
31
+ def execute_scp
32
+ user_to_use = @options[ :user ] || user
33
+ base = "scp -o StrictHostKeyChecking=no -i #{ key } "
34
+
35
+ if @options[ :direction ] == 'to'
36
+ command = base + "#{ @options[ :local_file ] } #{ user_to_use }@" +
37
+ "#{ instance_details[ :dns ] }:#{ @options[ :remote_file ] }"
38
+ else
39
+ command = base + "#{ user_to_use }@#{ instance_details[ :dns ] }" +
40
+ ":#{ @options[ :remote_file ] } #{ @options[ :local_file ] }"
41
+ end
42
+
43
+ exec command
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,29 @@
1
+ module UnimatrixCLI
2
+ module Citadel
3
+ module Instance
4
+ class SshCommand < CitadelCommand
5
+
6
+ option :instance, "Keyword for the name of the instance", type: :string, required: true
7
+ option :user, "Connect as a different user (optional)", type: :string
8
+ option :commands, "Remote commands (optional)", type: :string
9
+
10
+ synopsis "Enter ssh shell on the specified instance"
11
+
12
+ def execute
13
+ super
14
+ execute_shell
15
+ end
16
+
17
+ #----------------------------------------------------------------------------
18
+
19
+ def execute_shell
20
+ command = base_command
21
+ if @options[ :commands ]
22
+ command += " #{ @options[ :commands ] }"
23
+ end
24
+ exec command
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ module UnimatrixCLI
2
+ module Citadel
3
+ module Instance
4
+ class StatusCommand < CitadelCommand
5
+
6
+ option :instance, "Keyword for the name of the instance", type: :string, required: :true
7
+
8
+ synopsis "Display bluepill status for the specified instance"
9
+
10
+ def execute
11
+ super
12
+ execute_tunnel( 'bluepilld status' )
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module UnimatrixCLI
2
+ module Citadel
3
+ module Instance
4
+ class UserDataCommand < CitadelCommand
5
+
6
+ option :instance, "Keyword for the name of the instance", type: :string, required: :true
7
+
8
+ synopsis "Display user_data for the specified instance"
9
+
10
+ def execute
11
+ super
12
+ execute_tunnel( 'cat /tmp/user-data' )
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module UnimatrixCLI
2
+ module Citadel
3
+ module Instance
4
+ class UserDataLogsCommand < CitadelCommand
5
+
6
+ option :instance, "Keyword for the name of the instance", type: :string, required: :true
7
+
8
+ synopsis "Display user_data logs for the specified instance"
9
+
10
+ def execute
11
+ super
12
+ execute_tunnel( 'cat /var/log/user-data.log' )
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end