aptible-cli 0.19.3 → 0.19.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -1
- data/README.md +70 -64
- data/aptible-cli.gemspec +1 -0
- data/lib/aptible/cli/agent.rb +1 -0
- data/lib/aptible/cli/helpers/database.rb +13 -0
- data/lib/aptible/cli/helpers/operation.rb +41 -0
- data/lib/aptible/cli/helpers/s3_log_helpers.rb +225 -0
- data/lib/aptible/cli/subcommands/apps.rb +23 -0
- data/lib/aptible/cli/subcommands/db.rb +20 -0
- data/lib/aptible/cli/subcommands/environment.rb +19 -0
- data/lib/aptible/cli/subcommands/logs.rb +145 -0
- data/lib/aptible/cli/subcommands/metric_drain.rb +2 -1
- data/lib/aptible/cli/subcommands/operation.rb +33 -0
- data/lib/aptible/cli/version.rb +1 -1
- data/spec/aptible/cli/helpers/database_spec.rb +36 -0
- data/spec/aptible/cli/helpers/s3_log_helpers_spec.rb +334 -0
- data/spec/aptible/cli/subcommands/apps_spec.rb +41 -0
- data/spec/aptible/cli/subcommands/db_spec.rb +38 -0
- data/spec/aptible/cli/subcommands/environment_spec.rb +67 -32
- data/spec/aptible/cli/subcommands/logs_spec.rb +133 -0
- data/spec/aptible/cli/subcommands/metric_drain_spec.rb +1 -1
- data/spec/aptible/cli/subcommands/operation_spec.rb +172 -0
- data/spec/fabricators/operation_fabricator.rb +6 -1
- metadata +25 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc1a5d4d43d71792087a31f7994ed5a612dfe93ba90fd2ff3cebe63f5c8888a7
|
4
|
+
data.tar.gz: 7ac17167081e9edb3104b372a06622d736ce03051bb07279a690716eb7787ac9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b65bc6b0af2a8f88cc0fd72b47948ed01bbb3a32201ccaefd2b2dae3cdbe8042c6133e77862d79c63d4a0fa303460a5d453fa9f9a7ea7543af111a8101388fda
|
7
|
+
data.tar.gz: 7f8e3a443093b34b3b7428f249918e35327f92043cf0a35a248f7ef8aa8842f1a0d7ba8d48eeaa29f7d341be049f8f19e6b86d9d9ef91ea7401babaad2091fbf
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -28,70 +28,76 @@ From `aptible help`:
|
|
28
28
|
<!-- BEGIN USAGE -->
|
29
29
|
```
|
30
30
|
Commands:
|
31
|
-
aptible apps
|
32
|
-
aptible apps:create HANDLE
|
33
|
-
aptible apps:deprovision
|
34
|
-
aptible apps:
|
35
|
-
aptible
|
36
|
-
aptible backup:
|
37
|
-
aptible backup:
|
38
|
-
aptible backup:
|
39
|
-
aptible
|
40
|
-
aptible config
|
41
|
-
aptible config:
|
42
|
-
aptible config:
|
43
|
-
aptible config:
|
44
|
-
aptible
|
45
|
-
aptible db:
|
46
|
-
aptible db:
|
47
|
-
aptible db:
|
48
|
-
aptible db:
|
49
|
-
aptible db:
|
50
|
-
aptible db:
|
51
|
-
aptible db:
|
52
|
-
aptible db:
|
53
|
-
aptible db:
|
54
|
-
aptible db:
|
55
|
-
aptible db:
|
56
|
-
aptible db:
|
57
|
-
aptible db:
|
58
|
-
aptible
|
59
|
-
aptible
|
60
|
-
aptible
|
61
|
-
aptible endpoints:
|
62
|
-
aptible endpoints:
|
63
|
-
aptible endpoints:
|
64
|
-
aptible endpoints:
|
65
|
-
aptible endpoints:
|
66
|
-
aptible endpoints:
|
67
|
-
aptible endpoints:
|
68
|
-
aptible endpoints:
|
69
|
-
aptible endpoints:
|
70
|
-
aptible
|
71
|
-
aptible
|
72
|
-
aptible
|
73
|
-
aptible
|
74
|
-
aptible
|
75
|
-
aptible
|
76
|
-
aptible log_drain:create:
|
77
|
-
aptible log_drain:create:
|
78
|
-
aptible log_drain:create:
|
79
|
-
aptible log_drain:create:
|
80
|
-
aptible log_drain:
|
81
|
-
aptible log_drain:
|
82
|
-
aptible
|
83
|
-
aptible
|
84
|
-
aptible
|
85
|
-
aptible
|
86
|
-
aptible
|
87
|
-
aptible
|
88
|
-
aptible metric_drain:
|
89
|
-
aptible
|
90
|
-
aptible
|
91
|
-
aptible
|
92
|
-
aptible
|
93
|
-
aptible
|
94
|
-
aptible
|
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?
|
data/lib/aptible/cli/agent.rb
CHANGED
@@ -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
|