aptible-cli 0.19.3 → 0.19.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f20b71eb3388732ade1e6e53cb1f076761d40a06d460faf08fa3e468f239acc1
4
- data.tar.gz: 3e603d02a1dbe3e8168209f9a0f061d29851a48189d28dc549bff3a7d203a5e1
3
+ metadata.gz: bc1a5d4d43d71792087a31f7994ed5a612dfe93ba90fd2ff3cebe63f5c8888a7
4
+ data.tar.gz: 7ac17167081e9edb3104b372a06622d736ce03051bb07279a690716eb7787ac9
5
5
  SHA512:
6
- metadata.gz: e195096e2854788c488477ca6d42fd1beb15ce2b6044f0be32a774e6b3915c387694e4608c7546a94915dcb32b3f0844f4864544e4a64806dca23379c0383598
7
- data.tar.gz: b2fb1ef99eb836cac0e80419d362277b05877826e8cf4b8f8cb78f937168d4ab658b81f9fea6c7ea0559cd5fe6f926aec896869b7fa8737e4503536d39dfb161
6
+ metadata.gz: b65bc6b0af2a8f88cc0fd72b47948ed01bbb3a32201ccaefd2b2dae3cdbe8042c6133e77862d79c63d4a0fa303460a5d453fa9f9a7ea7543af111a8101388fda
7
+ data.tar.gz: 7f8e3a443093b34b3b7428f249918e35327f92043cf0a35a248f7ef8aa8842f1a0d7ba8d48eeaa29f7d341be049f8f19e6b86d9d9ef91ea7401babaad2091fbf
data/.travis.yml CHANGED
@@ -2,10 +2,12 @@ dist: xenial
2
2
  sudo: false
3
3
 
4
4
  rvm:
5
- - "2.0"
6
5
  - "2.1"
7
6
  - "2.2"
8
7
  - "2.3"
8
+ - "2.4"
9
+ - "2.5"
10
+ - "2.6"
9
11
 
10
12
  script:
11
13
  - bundle exec rake
data/README.md CHANGED
@@ -28,70 +28,76 @@ From `aptible help`:
28
28
  <!-- BEGIN USAGE -->
29
29
  ```
30
30
  Commands:
31
- aptible apps # List all applications
32
- aptible apps:create HANDLE # Create a new application
33
- aptible apps:deprovision # Deprovision an app
34
- aptible apps:scale SERVICE [--container-count COUNT] [--container-size SIZE_MB] # Scale a service
35
- aptible backup:list DB_HANDLE # List backups for a database
36
- aptible backup:orphaned # List backups associated with deprovisioned databases
37
- aptible backup:purge BACKUP_ID # Permanently delete a backup and any copies of it
38
- aptible backup:restore BACKUP_ID [--environment ENVIRONMENT_HANDLE] [--handle HANDLE] [--container-size SIZE_MB] [--disk-size SIZE_GB] [--key-arn KEY_ARN] # Restore a backup
39
- aptible config # Print an app's current configuration
40
- aptible config:add [VAR1=VAL1] [VAR2=VAL2] [...] # Add an ENV variable to an app
41
- aptible config:rm [VAR1] [VAR2] [...] # Remove an ENV variable from an app
42
- aptible config:set [VAR1=VAL1] [VAR2=VAL2] [...] # Add an ENV variable to an app
43
- aptible config:unset [VAR1] [VAR2] [...] # Remove an ENV variable from an app
44
- aptible db:backup HANDLE # Backup a database
45
- aptible db:clone SOURCE DEST # Clone a database to create a new one
46
- aptible db:create HANDLE [--type TYPE] [--version VERSION] [--container-size SIZE_MB] [--disk-size SIZE_GB] [--key-arn KEY_ARN] # Create a new database
47
- aptible db:deprovision HANDLE # Deprovision a database
48
- aptible db:dump HANDLE [pg_dump options] # Dump a remote database to file
49
- aptible db:execute HANDLE SQL_FILE [--on-error-stop] # Executes sql against a database
50
- aptible db:list # List all databases
51
- aptible db:modify HANDLE [--iops IOPS] [--volume-type [gp2, gp3]] # Modify a database disk
52
- aptible db:reload HANDLE # Reload a database
53
- aptible db:replicate HANDLE REPLICA_HANDLE [--container-size SIZE_MB] [--disk-size SIZE_GB] [--logical --version VERSION] [--key-arn KEY_ARN] # Create a replica/follower of a database
54
- aptible db:restart HANDLE [--container-size SIZE_MB] [--disk-size SIZE_GB] [--iops IOPS] [--volume-type [gp2, gp3]] # Restart a database
55
- aptible db:tunnel HANDLE # Create a local tunnel to a database
56
- aptible db:url HANDLE # Display a database URL
57
- aptible db:versions # List available database versions
58
- aptible deploy [OPTIONS] [VAR1=VAL1] [VAR2=VAL2] [...] # Deploy an app
59
- aptible endpoints:database:create DATABASE # Create a Database Endpoint
60
- aptible endpoints:database:modify --database DATABASE ENDPOINT_HOSTNAME # Modify a Database Endpoint
61
- aptible endpoints:deprovision [--app APP | --database DATABASE] ENDPOINT_HOSTNAME # Deprovision an App or Database Endpoint
62
- aptible endpoints:https:create [--app APP] SERVICE # Create an App HTTPS Endpoint
63
- aptible endpoints:https:modify [--app APP] ENDPOINT_HOSTNAME # Modify an App HTTPS Endpoint
64
- aptible endpoints:list [--app APP | --database DATABASE] # List Endpoints for an App or Database
65
- aptible endpoints:renew [--app APP] ENDPOINT_HOSTNAME # Renew an App Managed TLS Endpoint
66
- aptible endpoints:tcp:create [--app APP] SERVICE # Create an App TCP Endpoint
67
- aptible endpoints:tcp:modify [--app APP] ENDPOINT_HOSTNAME # Modify an App TCP Endpoint
68
- aptible endpoints:tls:create [--app APP] SERVICE # Create an App TLS Endpoint
69
- aptible endpoints:tls:modify [--app APP] ENDPOINT_HOSTNAME # Modify an App TLS Endpoint
70
- aptible environment:ca_cert # Retrieve the CA certificate associated with the environment
71
- aptible environment:list # List all environments
72
- aptible help [COMMAND] # Describe available commands or one specific command
73
- aptible log_drain:create:datadog HANDLE --url DATADOG_URL --environment ENVIRONMENT [--drain-apps true/false] [--drain_databases true/false] [--drain_ephemeral_sessions true/false] [--drain_proxies true/false] # Create a Datadog Log Drain
74
- aptible log_drain:create:elasticsearch HANDLE --db DATABASE_HANDLE --environment ENVIRONMENT [--drain-apps true/false] [--drain_databases true/false] [--drain_ephemeral_sessions true/false] [--drain_proxies true/false] # Create an Elasticsearch Log Drain
75
- aptible log_drain:create:https HANDLE --url URL --environment ENVIRONMENT [--drain-apps true/false] [--drain_databases true/false] [--drain_ephemeral_sessions true/false] [--drain_proxies true/false] # Create a HTTPS Drain
76
- aptible log_drain:create:logdna HANDLE --url LOGDNA_URL --environment ENVIRONMENT [--drain-apps true/false] [--drain_databases true/false] [--drain_ephemeral_sessions true/false] [--drain_proxies true/false] # Create a LogDNA Log Drain
77
- aptible log_drain:create:papertrail HANDLE --host PAPERTRAIL_HOST --port PAPERTRAIL_PORT --environment ENVIRONMENT [--drain-apps true/false] [--drain_databases true/false] [--drain_ephemeral_sessions true/false] [--drain_proxies true/false] # Create a Papertrail Log Drain
78
- aptible log_drain:create:sumologic HANDLE --url SUMOLOGIC_URL --environment ENVIRONMENT [--drain-apps true/false] [--drain_databases true/false] [--drain_ephemeral_sessions true/false] [--drain_proxies true/false] # Create a Sumologic Drain
79
- aptible log_drain:create:syslog HANDLE --host SYSLOG_HOST --port SYSLOG_PORT [--token TOKEN] --environment ENVIRONMENT [--drain-apps true/false] [--drain_databases true/false] [--drain_ephemeral_sessions true/false] [--drain_proxies true/false] # Create a Papertrail Log Drain
80
- aptible log_drain:deprovision HANDLE --environment ENVIRONMENT # Deprovisions a log drain
81
- aptible log_drain:list # List all Log Drains
82
- aptible login # Log in to Aptible
83
- aptible logs [--app APP | --database DATABASE] # Follows logs from a running app or database
84
- aptible metric_drain:create:datadog HANDLE --api_key DATADOG_API_KEY --site DATADOG_SITE --environment ENVIRONMENT # Create a Datadog Metric Drain
85
- aptible metric_drain:create:influxdb HANDLE --db DATABASE_HANDLE --environment ENVIRONMENT # Create an InfluxDB Metric Drain
86
- aptible metric_drain:create:influxdb:custom HANDLE --username USERNAME --password PASSWORD --url URL_INCLUDING_PORT --db INFLUX_DATABASE_NAME --environment ENVIRONMENT # Create an InfluxDB Metric Drain
87
- aptible metric_drain:deprovision HANDLE --environment ENVIRONMENT # Deprovisions a Metric Drain
88
- aptible metric_drain:list # List all Metric Drains
89
- aptible operation:cancel OPERATION_ID # Cancel a running operation
90
- aptible rebuild # Rebuild an app, and restart its services
91
- aptible restart # Restart all services associated with an app
92
- aptible services # List Services for an App
93
- aptible ssh [COMMAND] # Run a command against an app
94
- aptible version # Print Aptible CLI version
31
+ aptible apps # List all applications
32
+ aptible apps:create HANDLE # Create a new application
33
+ aptible apps:deprovision # Deprovision an app
34
+ aptible apps:rename OLD_HANDLE NEW_HANDLE [--environment ENVIRONMENT_HANDLE] # Rename an app handle. In order for the new app handle to appear in log drain and metric drain destinations, you must restart the app.
35
+ aptible apps:scale SERVICE [--container-count COUNT] [--container-size SIZE_MB] # Scale a service
36
+ aptible backup:list DB_HANDLE # List backups for a database
37
+ aptible backup:orphaned # List backups associated with deprovisioned databases
38
+ aptible backup:purge BACKUP_ID # Permanently delete a backup and any copies of it
39
+ aptible backup:restore BACKUP_ID [--environment ENVIRONMENT_HANDLE] [--handle HANDLE] [--container-size SIZE_MB] [--disk-size SIZE_GB] [--key-arn KEY_ARN] # Restore a backup
40
+ aptible config # Print an app's current configuration
41
+ aptible config:add [VAR1=VAL1] [VAR2=VAL2] [...] # Add an ENV variable to an app
42
+ aptible config:rm [VAR1] [VAR2] [...] # Remove an ENV variable from an app
43
+ aptible config:set [VAR1=VAL1] [VAR2=VAL2] [...] # Add an ENV variable to an app
44
+ aptible config:unset [VAR1] [VAR2] [...] # Remove an ENV variable from an app
45
+ aptible db:backup HANDLE # Backup a database
46
+ aptible db:clone SOURCE DEST # Clone a database to create a new one
47
+ aptible db:create HANDLE [--type TYPE] [--version VERSION] [--container-size SIZE_MB] [--disk-size SIZE_GB] [--key-arn KEY_ARN] # Create a new database
48
+ aptible db:deprovision HANDLE # Deprovision a database
49
+ aptible db:dump HANDLE [pg_dump options] # Dump a remote database to file
50
+ aptible db:execute HANDLE SQL_FILE [--on-error-stop] # Executes sql against a database
51
+ aptible db:list # List all databases
52
+ aptible db:modify HANDLE [--iops IOPS] [--volume-type [gp2, gp3]] # Modify a database disk
53
+ aptible db:reload HANDLE # Reload a database
54
+ aptible db:rename OLD_HANDLE NEW_HANDLE [--environment ENVIRONMENT_HANDLE] # Rename a database handle. In order for the new database handle to appear in log drain and metric drain destinations, you must reload the database.
55
+ aptible db:replicate HANDLE REPLICA_HANDLE [--container-size SIZE_MB] [--disk-size SIZE_GB] [--logical --version VERSION] [--key-arn KEY_ARN] # Create a replica/follower of a database
56
+ aptible db:restart HANDLE [--container-size SIZE_MB] [--disk-size SIZE_GB] [--iops IOPS] [--volume-type [gp2, gp3]] # Restart a database
57
+ aptible db:tunnel HANDLE # Create a local tunnel to a database
58
+ aptible db:url HANDLE # Display a database URL
59
+ aptible db:versions # List available database versions
60
+ aptible deploy [OPTIONS] [VAR1=VAL1] [VAR2=VAL2] [...] # Deploy an app
61
+ aptible endpoints:database:create DATABASE # Create a Database Endpoint
62
+ aptible endpoints:database:modify --database DATABASE ENDPOINT_HOSTNAME # Modify a Database Endpoint
63
+ aptible endpoints:deprovision [--app APP | --database DATABASE] ENDPOINT_HOSTNAME # Deprovision an App or Database Endpoint
64
+ aptible endpoints:https:create [--app APP] SERVICE # Create an App HTTPS Endpoint
65
+ aptible endpoints:https:modify [--app APP] ENDPOINT_HOSTNAME # Modify an App HTTPS Endpoint
66
+ aptible endpoints:list [--app APP | --database DATABASE] # List Endpoints for an App or Database
67
+ aptible endpoints:renew [--app APP] ENDPOINT_HOSTNAME # Renew an App Managed TLS Endpoint
68
+ aptible endpoints:tcp:create [--app APP] SERVICE # Create an App TCP Endpoint
69
+ aptible endpoints:tcp:modify [--app APP] ENDPOINT_HOSTNAME # Modify an App TCP Endpoint
70
+ aptible endpoints:tls:create [--app APP] SERVICE # Create an App TLS Endpoint
71
+ aptible endpoints:tls:modify [--app APP] ENDPOINT_HOSTNAME # Modify an App TLS Endpoint
72
+ aptible environment:ca_cert # Retrieve the CA certificate associated with the environment
73
+ aptible environment:list # List all environments
74
+ aptible environment:rename OLD_HANDLE NEW_HANDLE # Rename an environment handle. In order for the new environment handle to appear in log drain/metric destinations, you must restart the apps/databases in this environment.
75
+ aptible help [COMMAND] # Describe available commands or one specific command
76
+ aptible log_drain:create:datadog HANDLE --url DATADOG_URL --environment ENVIRONMENT [--drain-apps true/false] [--drain_databases true/false] [--drain_ephemeral_sessions true/false] [--drain_proxies true/false] # Create a Datadog Log Drain
77
+ aptible log_drain:create:elasticsearch HANDLE --db DATABASE_HANDLE --environment ENVIRONMENT [--drain-apps true/false] [--drain_databases true/false] [--drain_ephemeral_sessions true/false] [--drain_proxies true/false] # Create an Elasticsearch Log Drain
78
+ aptible log_drain:create:https HANDLE --url URL --environment ENVIRONMENT [--drain-apps true/false] [--drain_databases true/false] [--drain_ephemeral_sessions true/false] [--drain_proxies true/false] # Create a HTTPS Drain
79
+ aptible log_drain:create:logdna HANDLE --url LOGDNA_URL --environment ENVIRONMENT [--drain-apps true/false] [--drain_databases true/false] [--drain_ephemeral_sessions true/false] [--drain_proxies true/false] # Create a LogDNA Log Drain
80
+ aptible log_drain:create:papertrail HANDLE --host PAPERTRAIL_HOST --port PAPERTRAIL_PORT --environment ENVIRONMENT [--drain-apps true/false] [--drain_databases true/false] [--drain_ephemeral_sessions true/false] [--drain_proxies true/false] # Create a Papertrail Log Drain
81
+ aptible log_drain:create:sumologic HANDLE --url SUMOLOGIC_URL --environment ENVIRONMENT [--drain-apps true/false] [--drain_databases true/false] [--drain_ephemeral_sessions true/false] [--drain_proxies true/false] # Create a Sumologic Drain
82
+ aptible log_drain:create:syslog HANDLE --host SYSLOG_HOST --port SYSLOG_PORT [--token TOKEN] --environment ENVIRONMENT [--drain-apps true/false] [--drain_databases true/false] [--drain_ephemeral_sessions true/false] [--drain_proxies true/false] # Create a Papertrail Log Drain
83
+ aptible log_drain:deprovision HANDLE --environment ENVIRONMENT # Deprovisions a log drain
84
+ aptible log_drain:list # List all Log Drains
85
+ aptible login # Log in to Aptible
86
+ aptible logs [--app APP | --database DATABASE] # Follows logs from a running app or database
87
+ aptible logs_from_archive --bucket NAME --region REGION --stack NAME [ --decryption-keys ONE [OR MORE] ] [ --download-location LOCATION ] [ [ --string-matches ONE [OR MORE] ] | [ --app-id ID | --database-id ID | --endpoint-id ID | --container-id ID ] [ --start-date YYYY-MM-DD --end-date YYYY-MM-DD ] ] --bucket=BUCKET --region=REGION --stack=STACK # Retrieves container logs from an S3 archive in your own AWS account. You must provide your AWS credentials via the environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
88
+ aptible metric_drain:create:datadog HANDLE --api_key DATADOG_API_KEY --site DATADOG_SITE --environment ENVIRONMENT # Create a Datadog Metric Drain
89
+ aptible metric_drain:create:influxdb HANDLE --db DATABASE_HANDLE --environment ENVIRONMENT # Create an InfluxDB Metric Drain
90
+ aptible metric_drain:create:influxdb:custom HANDLE --username USERNAME --password PASSWORD --url URL_INCLUDING_PORT --db INFLUX_DATABASE_NAME --environment ENVIRONMENT # Create an InfluxDB Metric Drain
91
+ aptible metric_drain:deprovision HANDLE --environment ENVIRONMENT # Deprovisions a Metric Drain
92
+ aptible metric_drain:list # List all Metric Drains
93
+ aptible operation:cancel OPERATION_ID # Cancel a running operation
94
+ aptible operation:follow OPERATION_ID # Follow logs of a running operation
95
+ aptible operation:logs OPERATION_ID # View logs for given operation
96
+ aptible rebuild # Rebuild an app, and restart its services
97
+ aptible restart # Restart all services associated with an app
98
+ aptible services # List Services for an App
99
+ aptible ssh [COMMAND] # Run a command against an app
100
+ aptible version # Print Aptible CLI version
95
101
  ```
96
102
  <!-- END USAGE -->
97
103
 
data/aptible-cli.gemspec CHANGED
@@ -29,6 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.add_dependency 'term-ansicolor'
30
30
  spec.add_dependency 'chronic_duration', '~> 0.10.6'
31
31
  spec.add_dependency 'cbor'
32
+ spec.add_dependency 'aws-sdk', '~> 2.0'
32
33
 
33
34
  # Temporarily pin ffi until https://github.com/ffi/ffi/issues/868 is fixed
34
35
  spec.add_dependency 'ffi', '<= 1.14.1' if Gem.win_platform?
@@ -21,6 +21,7 @@ require_relative 'helpers/security_key'
21
21
  require_relative 'helpers/config_path'
22
22
  require_relative 'helpers/log_drain'
23
23
  require_relative 'helpers/metric_drain'
24
+ require_relative 'helpers/s3_log_helpers'
24
25
 
25
26
  require_relative 'subcommands/apps'
26
27
  require_relative 'subcommands/config'
@@ -154,6 +154,19 @@ module Aptible
154
154
  raise Thor::Error, err
155
155
  end
156
156
 
157
+ def validate_image_type(type)
158
+ available_types = []
159
+
160
+ Aptible::Api::DatabaseImage.all(token: fetch_token).each do |i|
161
+ return true if i.type == type
162
+ available_types << i.type
163
+ end
164
+
165
+ err = "No Database Image of type \"#{type}\""
166
+ err = "#{err}, valid types: #{available_types.uniq.join(', ')}"
167
+ raise Thor::Error, err
168
+ end
169
+
157
170
  def render_database(database, account)
158
171
  Formatter.render(Renderer.current) do |root|
159
172
  root.keyed_object('connection_url') do |node|
@@ -1,4 +1,5 @@
1
1
  require 'aptible/api'
2
+ require 'net/http'
2
3
 
3
4
  module Aptible
4
5
  module CLI
@@ -48,6 +49,15 @@ module Aptible
48
49
  operation.update!(cancelled: true)
49
50
  end
50
51
 
52
+ def operation_logs(operation)
53
+ res = get_operation_logs_redirect(operation)
54
+ s3_file_request = get_operation_logs_s3_file(res.body)
55
+
56
+ m = "Printing out results of operation logs for #{operation.id}"
57
+ CLI.logger.info m
58
+ puts s3_file_request.body
59
+ end
60
+
51
61
  def prettify_operation(o)
52
62
  bits = [o.status, o.type, "##{o.id}"]
53
63
  if o.resource.respond_to?(:handle)
@@ -55,6 +65,37 @@ module Aptible
55
65
  end
56
66
  bits.join ' '
57
67
  end
68
+
69
+ private
70
+
71
+ def get_operation_logs_redirect(operation)
72
+ uri = URI(operation.logs_url)
73
+ headers = { 'Authorization' => "Bearer #{fetch_token}" }
74
+ http = Net::HTTP.new(uri.host, uri.port)
75
+ http.use_ssl = true
76
+ res = http.request(Net::HTTP::Get.new(uri.request_uri, headers))
77
+ # note: res body with a 200 is target redirect location for download
78
+ if !res || res.code != '200' || res.body.nil?
79
+ raise Thor::Error, 'Unable to retrieve the operation\'s logs. '\
80
+ 'If the issue persists please contact support for assistance.'
81
+ end
82
+ res
83
+ end
84
+
85
+ def get_operation_logs_s3_file(location)
86
+ s3_uri = URI(location)
87
+ http = Net::HTTP.new(s3_uri.host, s3_uri.port)
88
+ http.use_ssl = true
89
+
90
+ # follow the link with redirect and retrieve it from s3 directly
91
+ res = http.request(Net::HTTP::Get.new(s3_uri.request_uri))
92
+ if !res || res.code != '200'
93
+ raise Thor::Error, 'Unable to retrieve operation logs, '\
94
+ "S3 returned response code #{res.code}. "\
95
+ 'If the issue persists please contact support for assistance.'
96
+ end
97
+ res
98
+ end
58
99
  end
59
100
  end
60
101
  end
@@ -0,0 +1,225 @@
1
+ require 'aws-sdk'
2
+ require 'pathname'
3
+
4
+ module Aptible
5
+ module CLI
6
+ module Helpers
7
+ module S3LogHelpers
8
+ def ensure_aws_creds
9
+ cred_errors = []
10
+ unless ENV['AWS_ACCESS_KEY_ID']
11
+ cred_errors << 'Missing environment variable: AWS_ACCESS_KEY_ID'
12
+ end
13
+ unless ENV['AWS_SECRET_ACCESS_KEY']
14
+ cred_errors << 'Missing environment variable: AWS_SECRET_ACCESS_KEY'
15
+ end
16
+ raise Thor::Error, cred_errors.join(' ') if cred_errors.any?
17
+ end
18
+
19
+ def validate_log_search_options(options = {})
20
+ id_options = [
21
+ options[:app_id],
22
+ options[:database_id],
23
+ options[:endpoint_id],
24
+ options[:container_id]
25
+ ]
26
+ date_options = [options[:start_date], options[:end_date]]
27
+ unless options[:string_matches] || id_options.any?
28
+ m = 'You must specify an option to identify the logs to download,' \
29
+ ' either: --string-matches, --app-id, --database-id,' \
30
+ ' --endpoint-id, or --container-id'
31
+ raise Thor::Error, m
32
+ end
33
+
34
+ m = 'You cannot pass --app-id, --database-id, --endpoint-id, or ' \
35
+ '--container-id when using --string-matches.'
36
+ raise Thor::Error, m if options[:string_matches] && id_options.any?
37
+
38
+ m = 'You must specify only one of ' \
39
+ '--app-id, --database-id, --endpoint-id or --container-id'
40
+ raise Thor::Error, m if id_options.any? && !id_options.one?
41
+
42
+ m = 'The options --start-date/--end-date cannot be used when ' \
43
+ 'searching by string'
44
+ raise Thor::Error, m if options[:string_matches] && date_options.any?
45
+
46
+ m = 'You must pass both --start-date and --end-date'
47
+ raise Thor::Error, m if date_options.any? && !date_options.all?
48
+
49
+ if options[:container_id] && options[:container_id].length < 12
50
+ m = 'You must specify at least the first 12 characters of the ' \
51
+ 'container ID'
52
+ raise Thor::Error, m
53
+ end
54
+
55
+ if options[:download_location] && !options[:decryption_keys]
56
+ m = 'You must provide decryption keys with the --decryption-keys' \
57
+ 'option in order to download files.'
58
+ raise Thor::Error, m
59
+ end
60
+ end
61
+
62
+ def info_from_path(file)
63
+ properties = {}
64
+
65
+ properties[:stack], _, properties[:schema],
66
+ properties[:shasum], type_id, *remainder = file.split('/')
67
+
68
+ properties[:id] = type_id.split('-').last.to_i
69
+ properties[:type] = type_id.split('-').first
70
+
71
+ case properties[:schema]
72
+ when 'v2'
73
+ # Eliminate the extensions
74
+ split_by_dot = remainder.pop.split('.') - %w(log bck gz)
75
+ properties[:container_id] = split_by_dot.first.delete!('-json')
76
+ properties[:uploaded_at] = utc_datetime(split_by_dot.last)
77
+ when 'v3'
78
+ case properties[:type]
79
+ when 'apps'
80
+ properties[:service_id] = remainder.first.split('-').last.to_i
81
+ file_name = remainder.second
82
+ else
83
+ file_name = remainder.first
84
+ end
85
+ # The file name may have differing number of elements due to
86
+ # docker file log rotation. So we eliminate some useless items
87
+ # and then work from the beginning or end of the remaining to find
88
+ # known elements, ignoring any .1 .2 (or none at all) extension
89
+ # found in the middle of the file name. EG:
90
+ # ['container_id', 'start_time', 'end_time']
91
+ # or
92
+ # ['container_id', '.1', 'start_time', 'end_time']]
93
+ split_by_dot = file_name.split('.') - %w(log gz archived)
94
+ properties[:container_id] = split_by_dot.first.delete!('-json')
95
+ properties[:start_time] = utc_datetime(split_by_dot[-2])
96
+ properties[:end_time] = utc_datetime(split_by_dot[-1])
97
+ else
98
+ m = "Cannot determine aptible log naming schema from #{file}"
99
+ raise Thor::Error, m
100
+ end
101
+ properties
102
+ end
103
+
104
+ def decrypt_and_translate_s3_file(file, enc_key, region, bucket, path)
105
+ # AWS warns us about using the legacy encryption schema
106
+ s3 = Kernel.silence_warnings do
107
+ Aws::S3::EncryptionV2::Client.new(
108
+ encryption_key: enc_key, region: region,
109
+ key_wrap_schema: :aes_gcm,
110
+ content_encryption_schema: :aes_gcm_no_padding,
111
+ security_profile: :v2_and_legacy
112
+ )
113
+ end
114
+
115
+ # Just write it to a file directly
116
+ location = File.join(path, file.split('/').drop(4).join('/'))
117
+ FileUtils.mkdir_p(File.dirname(location))
118
+ File.open(location, 'wb') do |f|
119
+ CLI.logger.info location
120
+ # Is this memory efficient?
121
+ s3.get_object(bucket: bucket, key: file, response_target: f)
122
+ end
123
+ end
124
+
125
+ def find_s3_files_by_string_match(region, bucket, stack, strings)
126
+ # This function just regex matches a provided string anywhwere
127
+ # in the s3 path
128
+ begin
129
+ stack_logs = s3_client(region).bucket(bucket)
130
+ .objects(prefix: stack)
131
+ .map(&:key)
132
+ rescue => error
133
+ raise Thor::Error, error.message
134
+ end
135
+ strings.each do |s|
136
+ stack_logs = stack_logs.select { |f| f =~ /#{s}/ }
137
+ end
138
+ stack_logs
139
+ end
140
+
141
+ def find_s3_files_by_attrs(region, bucket, stack,
142
+ attrs, time_range = nil)
143
+ # This function uses the known path schema to return files matching
144
+ # any provided criteria. EG:
145
+ # * attrs: { :type => 'app', :id => 123 }
146
+ # * attrs: { :container_id => 'deadbeef' }
147
+
148
+ begin
149
+ stack_logs = s3_client(region).bucket(bucket)
150
+ .objects(prefix: stack)
151
+ .map(&:key)
152
+ rescue => error
153
+ raise Thor::Error, error.message
154
+ end
155
+ attrs.each do |k, v|
156
+ stack_logs = stack_logs.select do |f|
157
+ if k == :container_id
158
+ # Match short container IDs
159
+ info_from_path(f)[k].start_with?(v)
160
+ else
161
+ info_from_path(f)[k] == v
162
+ end
163
+ end
164
+ end
165
+
166
+ if time_range
167
+ # select only logs within the time range
168
+ stack_logs = stack_logs.select do |f|
169
+ info = info_from_path(f)
170
+ first_log = info[:start_time]
171
+ last_log = info[:end_time]
172
+ if first_log.nil? || last_log.nil?
173
+ m = 'Cannot determine precise timestamps of file: ' \
174
+ "#{f.split('/').drop(4).join('/')}"
175
+ CLI.logger.warn m
176
+ false
177
+ else
178
+ time_match?(time_range, first_log, last_log)
179
+ end
180
+ end
181
+ end
182
+
183
+ stack_logs
184
+ end
185
+
186
+ def time_match?(time_range, start_timestamp, end_timestamp)
187
+ return false if start_timestamp.nil? || end_timestamp.nil?
188
+ return false if time_range.last < start_timestamp
189
+ return false if time_range.first > end_timestamp
190
+ true
191
+ end
192
+
193
+ def utc_date(date_string)
194
+ t_fmt = '%Y-%m-%d %Z'
195
+ Time.strptime("#{date_string} UTC", t_fmt)
196
+ rescue ArgumentError
197
+ raise Thor::Error, 'Please provide dates in YYYY-MM-DD format'
198
+ end
199
+
200
+ def utc_datetime(datetime_string)
201
+ Time.parse("#{datetime_string}Z")
202
+ rescue ArgumentError
203
+ nil
204
+ end
205
+
206
+ def encryption_key(filesum, possible_keys)
207
+ # The key can be determined from the sum
208
+ possible_keys.each do |k|
209
+ keysum = Digest::SHA256.hexdigest(Base64.strict_decode64(k))
210
+ next unless keysum == filesum
211
+ return Base64.strict_decode64(k)
212
+ end
213
+ m = "Did not find a matching key for shasum #{filesum}"
214
+ raise Thor::Error, m
215
+ end
216
+
217
+ def s3_client(region)
218
+ @s3_client ||= Kernel.silence_warnings do
219
+ Aws::S3::Resource.new(region: region)
220
+ end
221
+ end
222
+ end
223
+ end
224
+ end
225
+ end
@@ -94,6 +94,29 @@ module Aptible
94
94
  raise if e.response.status != 404
95
95
  end
96
96
  end
97
+
98
+ desc 'apps:rename OLD_HANDLE NEW_HANDLE [--environment'\
99
+ ' ENVIRONMENT_HANDLE]', 'Rename an app handle. In order'\
100
+ ' for the new app handle to appear in log drain and metric'\
101
+ ' drain destinations, you must restart the app.'
102
+ option :environment
103
+ define_method 'apps:rename' do |old_handle, new_handle|
104
+ env = ensure_environment(options)
105
+ app = ensure_app(options.merge(app: old_handle))
106
+ app.update!(handle: new_handle)
107
+ m1 = "In order for the new app name (#{new_handle}) to appear"\
108
+ ' in log drain and metric drain destinations, you must'\
109
+ ' restart the app.'
110
+ m2 = 'You can restart your app with this command: "aptible '\
111
+ "restart --app #{new_handle} --environment #{env.handle}\""
112
+ m3 = 'Warning - Git remote addresses must be updated to match'\
113
+ ' the new handle, if using Dockerfile deploy. '\
114
+ "(git@beta.aptible.com:#{app.account.handle}"\
115
+ "/#{new_handle}.git)"
116
+ CLI.logger.warn m1
117
+ CLI.logger.info m2
118
+ CLI.logger.warn m3
119
+ end
97
120
  end
98
121
  end
99
122
  end