aptible-cli 0.19.6 → 0.19.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -0
- data/README.md +8 -7
- data/SECURITY.md +23 -0
- data/aptible-cli.gemspec +2 -1
- data/cleanup_bundler +14 -0
- data/lib/aptible/cli/agent.rb +5 -0
- data/lib/aptible/cli/helpers/date_helpers.rb +34 -0
- data/lib/aptible/cli/helpers/maintenance.rb +19 -0
- data/lib/aptible/cli/helpers/s3_log_helpers.rb +2 -13
- data/lib/aptible/cli/resource_formatter.rb +25 -2
- data/lib/aptible/cli/subcommands/deploy.rb +1 -1
- data/lib/aptible/cli/subcommands/logs.rb +1 -0
- data/lib/aptible/cli/subcommands/maintenance.rb +97 -0
- data/lib/aptible/cli/subcommands/metric_drain.rb +30 -0
- data/lib/aptible/cli/version.rb +1 -1
- data/spec/aptible/cli/helpers/date_helpers_spec.rb +12 -0
- data/spec/aptible/cli/subcommands/maintenance_spec.rb +189 -0
- data/spec/aptible/cli/subcommands/metric_drain_spec.rb +27 -1
- data/spec/fabricators/maintenance_app_fabricator.rb +10 -0
- data/spec/fabricators/maintenance_database_fabricator.rb +10 -0
- metadata +32 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5297ec1eb7d106b2b69705d31ab05426fb64d8c553b170918c4090aaf582398f
|
4
|
+
data.tar.gz: d0478f4e443b88f9def1a45a9db9b029f62d36e6d73bc53c6a686c858bfd3e83
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e0490170403f7272b481a09272115aafc5d1a3c65b21c26d357e149fc305b5ffef0c04903d8e677f865b992d76551828e3621a338d2bc6c6ee69a33222b8ddf
|
7
|
+
data.tar.gz: fa77c4fd5462b8b99a5f0ae8146e876e163e8faf6b2e34aa1275cdbea6d920d40b48b9f1fb08820b92d3b5ab02de681c17b20a4192305b7c674760cdfbd80ba3
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,7 @@
|
|
1
|
-
|
1
|
+
<br>
|
2
|
+
<img src="https://user-images.githubusercontent.com/4295811/226700092-ffbd0c01-dba1-4880-8b77-a4d26e6228f0.svg" width="64">
|
2
3
|
|
3
|
-
|
4
|
-
[![Build Status](https://travis-ci.org/aptible/aptible-cli.png?branch=master)](https://travis-ci.org/aptible/aptible-cli)
|
5
|
-
[![Dependency Status](https://gemnasium.com/aptible/aptible-cli.png)](https://gemnasium.com/aptible/aptible-cli)
|
6
|
-
[![Roadmap](https://badge.waffle.io/aptible/aptible-cli.svg?label=ready&title=roadmap)](http://waffle.io/aptible/aptible-cli)
|
4
|
+
# Aptible CLI
|
7
5
|
|
8
6
|
Command-line interface for Aptible services.
|
9
7
|
|
@@ -11,8 +9,8 @@ Command-line interface for Aptible services.
|
|
11
9
|
|
12
10
|
**NOTE: To install the `aptible` tool as a system-level binary, Aptible
|
13
11
|
recommends you install the
|
14
|
-
[Aptible
|
15
|
-
and more robust.
|
12
|
+
[Aptible CLI](https://www.aptible.com/docs/cli)** directly, which is
|
13
|
+
faster and more robust.
|
16
14
|
|
17
15
|
Add the following line to your application's Gemfile.
|
18
16
|
|
@@ -85,9 +83,12 @@ Commands:
|
|
85
83
|
aptible login # Log in to Aptible
|
86
84
|
aptible logs [--app APP | --database DATABASE] # Follows logs from a running app or database
|
87
85
|
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
|
86
|
+
aptible maintenance:apps # List Apps impacted by maintenance schedules where restarts are required
|
87
|
+
aptible maintenance:dbs # List Databases impacted by maintenance schedules where restarts are required
|
88
88
|
aptible metric_drain:create:datadog HANDLE --api_key DATADOG_API_KEY --site DATADOG_SITE --environment ENVIRONMENT # Create a Datadog Metric Drain
|
89
89
|
aptible metric_drain:create:influxdb HANDLE --db DATABASE_HANDLE --environment ENVIRONMENT # Create an InfluxDB Metric Drain
|
90
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:create:influxdb:customv2 HANDLE --org ORGANIZATION --token INFLUX_TOKEN --url URL_INCLUDING_PORT --bucket INFLUX_BUCKET_NAME --environment ENVIRONMENT # Create an InfluxDB v2 Metric Drain
|
91
92
|
aptible metric_drain:deprovision HANDLE --environment ENVIRONMENT # Deprovisions a Metric Drain
|
92
93
|
aptible metric_drain:list # List all Metric Drains
|
93
94
|
aptible operation:cancel OPERATION_ID # Cancel a running operation
|
data/SECURITY.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Aptible Open Source Security Policies and Procedures
|
2
|
+
|
3
|
+
This document outlines security procedures and general policies for the Aptible open source projects as found on https://github.com/aptible.
|
4
|
+
|
5
|
+
* [Reporting a Vulnerability](#reporting-a-vulnerability)
|
6
|
+
* [Responsible Disclosure Policy](#responsible-disclosure-policy)
|
7
|
+
|
8
|
+
## Reporting a Vulnerability
|
9
|
+
|
10
|
+
The Aptible team and community take all security vulnerabilities
|
11
|
+
seriously. Thank you for improving the security of our open source software. We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions.
|
12
|
+
|
13
|
+
Report security vulnerabilities by emailing the Aptible security team at:
|
14
|
+
|
15
|
+
security@aptible.com
|
16
|
+
|
17
|
+
Security researchers can also privately report security vulnerabilities to repository maintainers using the GitHub "Report a Vulnerability" feature. [See how-to here](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability).
|
18
|
+
|
19
|
+
The Aptible team will acknowledge your email within 24 business hours and send a detailed response within 48 business hours indicating the next steps in handling your report. The Aptible security team will keep you informed of the progress and may ask for additional information or guidance.
|
20
|
+
|
21
|
+
## Responsible Disclosure Policy
|
22
|
+
|
23
|
+
Please see Aptible's Responsible Disclosure Policy here: https://www.aptible.com/legal/responsible-disclosure/
|
data/aptible-cli.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.require_paths = ['lib']
|
22
22
|
|
23
23
|
spec.add_dependency 'aptible-resource', '~> 1.1'
|
24
|
-
spec.add_dependency 'aptible-api', '~> 1.
|
24
|
+
spec.add_dependency 'aptible-api', '~> 1.4'
|
25
25
|
spec.add_dependency 'aptible-auth', '~> 1.2.4'
|
26
26
|
spec.add_dependency 'aptible-billing', '~> 1.0'
|
27
27
|
spec.add_dependency 'thor', '~> 0.20.0'
|
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_dependency 'chronic_duration', '~> 0.10.6'
|
31
31
|
spec.add_dependency 'cbor'
|
32
32
|
spec.add_dependency 'aws-sdk', '~> 2.0'
|
33
|
+
spec.add_dependency 'bigdecimal', '~> 1.3.5' # https://github.com/ruby/bigdecimal#which-version-should-you-select
|
33
34
|
|
34
35
|
# Temporarily pin ffi until https://github.com/ffi/ffi/issues/868 is fixed
|
35
36
|
spec.add_dependency 'ffi', '<= 1.14.1' if Gem.win_platform?
|
data/cleanup_bundler
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Newer rubies have Bundler 2.x installed as default so it can't be deleted
|
4
|
+
# We need Bundler 1.x
|
5
|
+
|
6
|
+
gempaths = `gem env gempath`.split(':')
|
7
|
+
gempaths.each do |gempath|
|
8
|
+
# lookup bundler-*.gemspec files and delete them
|
9
|
+
# this is the only way to completely cleanup default bundler
|
10
|
+
# Note: the bundler gemspecs' paths are different for CRuby and JRuby
|
11
|
+
Dir.glob(gempath.strip + '/specifications/**/bundler-*.gemspec').each do |p|
|
12
|
+
File.delete(p)
|
13
|
+
end
|
14
|
+
end
|
data/lib/aptible/cli/agent.rb
CHANGED
@@ -21,7 +21,9 @@ 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/date_helpers'
|
24
25
|
require_relative 'helpers/s3_log_helpers'
|
26
|
+
require_relative 'helpers/maintenance'
|
25
27
|
|
26
28
|
require_relative 'subcommands/apps'
|
27
29
|
require_relative 'subcommands/config'
|
@@ -39,6 +41,7 @@ require_relative 'subcommands/inspect'
|
|
39
41
|
require_relative 'subcommands/endpoints'
|
40
42
|
require_relative 'subcommands/log_drain'
|
41
43
|
require_relative 'subcommands/metric_drain'
|
44
|
+
require_relative 'subcommands/maintenance'
|
42
45
|
|
43
46
|
module Aptible
|
44
47
|
module CLI
|
@@ -49,6 +52,7 @@ module Aptible
|
|
49
52
|
include Helpers::Ssh
|
50
53
|
include Helpers::System
|
51
54
|
include Helpers::ConfigPath
|
55
|
+
include Helpers::DateHelpers
|
52
56
|
include Subcommands::Apps
|
53
57
|
include Subcommands::Config
|
54
58
|
include Subcommands::DB
|
@@ -65,6 +69,7 @@ module Aptible
|
|
65
69
|
include Subcommands::Endpoints
|
66
70
|
include Subcommands::LogDrain
|
67
71
|
include Subcommands::MetricDrain
|
72
|
+
include Subcommands::Maintenance
|
68
73
|
|
69
74
|
# Forward return codes on failures.
|
70
75
|
def self.exit_on_failure?
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Aptible
|
2
|
+
module CLI
|
3
|
+
module Helpers
|
4
|
+
module DateHelpers
|
5
|
+
# This should only be used by the method processing user date input in
|
6
|
+
# S3LogHelpers. It is used to process a user-provided string into UTC.
|
7
|
+
def utc_date(date_string)
|
8
|
+
t_fmt = '%Y-%m-%d %Z'
|
9
|
+
Time.strptime("#{date_string} UTC", t_fmt)
|
10
|
+
rescue ArgumentError
|
11
|
+
raise Thor::Error, 'Please provide dates in YYYY-MM-DD format'
|
12
|
+
end
|
13
|
+
|
14
|
+
# This should only be used by the method processing timestamps from S3
|
15
|
+
# file names in S3LogHelpers. The file name does not include any time
|
16
|
+
# zone information, but we know it to be in UTC, so we add the "Z"
|
17
|
+
def utc_datetime(datetime_string)
|
18
|
+
Time.parse("#{datetime_string}Z")
|
19
|
+
rescue ArgumentError
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
# This is used to format timestamps returned by our API into a more
|
24
|
+
# readable format.
|
25
|
+
# EG, "2023-09-05T22:00:00.000Z" returns "2023-09-05 22:00:00 UTC"
|
26
|
+
def utc_string(datetime_string)
|
27
|
+
Time.parse(datetime_string)
|
28
|
+
rescue ArgumentError
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'aptible/api'
|
2
|
+
|
3
|
+
module Aptible
|
4
|
+
module CLI
|
5
|
+
module Helpers
|
6
|
+
module Maintenance
|
7
|
+
include Helpers::Token
|
8
|
+
|
9
|
+
def maintenance_apps
|
10
|
+
Aptible::Api::MaintenanceApp.all(token: fetch_token)
|
11
|
+
end
|
12
|
+
|
13
|
+
def maintenance_databases
|
14
|
+
Aptible::Api::MaintenanceDatabase.all(token: fetch_token)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -5,6 +5,8 @@ module Aptible
|
|
5
5
|
module CLI
|
6
6
|
module Helpers
|
7
7
|
module S3LogHelpers
|
8
|
+
include Helpers::DateHelpers
|
9
|
+
|
8
10
|
def ensure_aws_creds
|
9
11
|
cred_errors = []
|
10
12
|
unless ENV['AWS_ACCESS_KEY_ID']
|
@@ -190,19 +192,6 @@ module Aptible
|
|
190
192
|
true
|
191
193
|
end
|
192
194
|
|
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
195
|
def encryption_key(filesum, possible_keys)
|
207
196
|
# The key can be determined from the sum
|
208
197
|
possible_keys.each do |k|
|
@@ -2,6 +2,8 @@ module Aptible
|
|
2
2
|
module CLI
|
3
3
|
module ResourceFormatter
|
4
4
|
class << self
|
5
|
+
include Helpers::DateHelpers
|
6
|
+
|
5
7
|
NO_NESTING = Object.new.freeze
|
6
8
|
|
7
9
|
def inject_backup(node, backup, include_db: false)
|
@@ -50,8 +52,7 @@ module Aptible
|
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
53
|
-
if bu_operation &&
|
54
|
-
backup.manual && !backup.copied_from
|
55
|
+
if bu_operation && !backup.copied_from
|
55
56
|
node.keyed_object('created_from_operation', 'id') do |n|
|
56
57
|
inject_operation(n, bu_operation)
|
57
58
|
end
|
@@ -236,6 +237,28 @@ module Aptible
|
|
236
237
|
attach_account(node, account)
|
237
238
|
end
|
238
239
|
|
240
|
+
def inject_maintenance(
|
241
|
+
node,
|
242
|
+
command_prefix,
|
243
|
+
maintenance_resource,
|
244
|
+
account
|
245
|
+
)
|
246
|
+
node.value('id', maintenance_resource.id)
|
247
|
+
raw_start, raw_end = maintenance_resource.maintenance_deadline
|
248
|
+
window_start = utc_string(raw_start)
|
249
|
+
window_end = utc_string(raw_end)
|
250
|
+
label = "#{maintenance_resource.handle} between #{window_start} "\
|
251
|
+
"and #{window_end}"
|
252
|
+
restart_command = "#{command_prefix}"\
|
253
|
+
" #{maintenance_resource.handle}"\
|
254
|
+
" --environment #{account.handle}"
|
255
|
+
node.value('label', label)
|
256
|
+
node.value('handle', maintenance_resource.handle)
|
257
|
+
node.value('restart_command', restart_command)
|
258
|
+
|
259
|
+
attach_account(node, account)
|
260
|
+
end
|
261
|
+
|
239
262
|
private
|
240
263
|
|
241
264
|
def attach_account(node, account)
|
@@ -41,7 +41,7 @@ module Aptible
|
|
41
41
|
git_ref = options[:git_commitish]
|
42
42
|
if options[:git_detach]
|
43
43
|
if git_ref
|
44
|
-
raise Thor::Error, 'The options --git-
|
44
|
+
raise Thor::Error, 'The options --git-commitish and ' \
|
45
45
|
'--git-detach are incompatible'
|
46
46
|
end
|
47
47
|
git_ref = NULL_SHA1
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Aptible
|
2
|
+
module CLI
|
3
|
+
module Subcommands
|
4
|
+
module Maintenance
|
5
|
+
def self.included(thor)
|
6
|
+
thor.class_eval do
|
7
|
+
include Helpers::Environment
|
8
|
+
include Helpers::Maintenance
|
9
|
+
include Helpers::Token
|
10
|
+
|
11
|
+
desc 'maintenance:apps',
|
12
|
+
'List Apps impacted by maintenance schedules where '\
|
13
|
+
'restarts are required'
|
14
|
+
option :environment
|
15
|
+
define_method 'maintenance:apps' do
|
16
|
+
found_maintenance = false
|
17
|
+
m = maintenance_apps
|
18
|
+
Formatter.render(Renderer.current) do |root|
|
19
|
+
root.grouped_keyed_list(
|
20
|
+
{ 'environment' => 'handle' },
|
21
|
+
'label'
|
22
|
+
) do |node|
|
23
|
+
scoped_environments(options).each do |account|
|
24
|
+
m.select { |app| app.account.id == account.id }
|
25
|
+
.each do |app|
|
26
|
+
next unless app.maintenance_deadline
|
27
|
+
found_maintenance = true
|
28
|
+
node.object do |n|
|
29
|
+
ResourceFormatter.inject_maintenance(
|
30
|
+
n,
|
31
|
+
'aptible restart --app',
|
32
|
+
app,
|
33
|
+
account
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
if found_maintenance
|
41
|
+
explanation 'app'
|
42
|
+
else
|
43
|
+
no_maintenances 'app'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
desc 'maintenance:dbs',
|
47
|
+
'List Databases impacted by maintenance schedules where '\
|
48
|
+
'restarts are required'
|
49
|
+
option :environment
|
50
|
+
define_method 'maintenance:dbs' do
|
51
|
+
found_maintenance = false
|
52
|
+
m = maintenance_databases
|
53
|
+
Formatter.render(Renderer.current) do |root|
|
54
|
+
root.grouped_keyed_list(
|
55
|
+
{ 'environment' => 'handle' },
|
56
|
+
'label'
|
57
|
+
) do |node|
|
58
|
+
scoped_environments(options).each do |account|
|
59
|
+
m.select { |db| db.account.id == account.id }
|
60
|
+
.each do |db|
|
61
|
+
next unless db.maintenance_deadline
|
62
|
+
found_maintenance = true
|
63
|
+
node.object do |n|
|
64
|
+
ResourceFormatter.inject_maintenance(
|
65
|
+
n,
|
66
|
+
'aptible db:restart',
|
67
|
+
db,
|
68
|
+
account
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
if found_maintenance
|
76
|
+
explanation 'database'
|
77
|
+
else
|
78
|
+
no_maintenances 'database'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def explanation(resource_type)
|
85
|
+
CLI.logger.warn "\nYou may restart these #{resource_type}(s)"\
|
86
|
+
' at any time, or Aptible will restart it'\
|
87
|
+
' during the defined window.'
|
88
|
+
end
|
89
|
+
|
90
|
+
def no_maintenances(resource_type)
|
91
|
+
CLI.logger.info "\nNo #{resource_type}s found affected "\
|
92
|
+
'by maintenance schedules.'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -5,6 +5,7 @@ module Aptible
|
|
5
5
|
SITES = {
|
6
6
|
'US1' => 'https://app.datadoghq.com',
|
7
7
|
'US3' => 'https://us3.datadoghq.com',
|
8
|
+
'US5' => 'https://us5.datadoghq.com',
|
8
9
|
'EU1' => 'https://app.datadoghq.eu',
|
9
10
|
'US1-FED' => 'https://app.ddog-gov.com'
|
10
11
|
}.freeze
|
@@ -84,6 +85,35 @@ module Aptible
|
|
84
85
|
create_metric_drain(account, opts)
|
85
86
|
end
|
86
87
|
|
88
|
+
desc 'metric_drain:create:influxdb:customv2 HANDLE '\
|
89
|
+
'--org ORGANIZATION --token INFLUX_TOKEN ' \
|
90
|
+
'--url URL_INCLUDING_PORT ' \
|
91
|
+
'--bucket INFLUX_BUCKET_NAME ' \
|
92
|
+
'--environment ENVIRONMENT',
|
93
|
+
'Create an InfluxDB v2 Metric Drain'
|
94
|
+
option :bucket, type: :string
|
95
|
+
option :org, type: :string
|
96
|
+
option :token, type: :string
|
97
|
+
option :url, type: :string
|
98
|
+
option :environment
|
99
|
+
define_method 'metric_drain:create:influxdb:customv2' do |handle|
|
100
|
+
account = ensure_environment(options)
|
101
|
+
|
102
|
+
config = {
|
103
|
+
address: options[:url],
|
104
|
+
org: options[:org],
|
105
|
+
authToken: options[:token],
|
106
|
+
bucket: options[:bucket]
|
107
|
+
}
|
108
|
+
opts = {
|
109
|
+
handle: handle,
|
110
|
+
drain_configuration: config,
|
111
|
+
drain_type: :influxdb2
|
112
|
+
}
|
113
|
+
|
114
|
+
create_metric_drain(account, opts)
|
115
|
+
end
|
116
|
+
|
87
117
|
desc 'metric_drain:create:datadog HANDLE '\
|
88
118
|
'--api_key DATADOG_API_KEY '\
|
89
119
|
'--site DATADOG_SITE ' \
|
data/lib/aptible/cli/version.rb
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Aptible::CLI::Helpers::DateHelpers do
|
4
|
+
subject { Class.new.send(:include, described_class).new }
|
5
|
+
|
6
|
+
describe '#utc_string' do
|
7
|
+
it 'should accept a Datetime string from our API and return a UTC string' do
|
8
|
+
result = subject.utc_string('2023-09-05T22:00:00.000Z')
|
9
|
+
expect(result).to eq '2023-09-05 22:00:00 UTC'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Aptible::CLI::Agent do
|
4
|
+
include Aptible::CLI::Helpers::DateHelpers
|
5
|
+
|
6
|
+
let(:token) { double('token') }
|
7
|
+
|
8
|
+
before do
|
9
|
+
allow(subject).to receive(:ask)
|
10
|
+
allow(subject).to receive(:save_token)
|
11
|
+
allow(subject).to receive(:fetch_token) { token }
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:handle) { 'foobar' }
|
15
|
+
let(:stack) { Fabricate(:stack, internal_domain: 'aptible.in') }
|
16
|
+
let(:account) { Fabricate(:account, stack: stack) }
|
17
|
+
let(:database) { Fabricate(:database, handle: handle, account: account) }
|
18
|
+
let(:staging) { Fabricate(:account, handle: 'staging') }
|
19
|
+
let(:prod) { Fabricate(:account, handle: 'production') }
|
20
|
+
let(:window_start) { '2073-09-05T22:00:00.000Z' }
|
21
|
+
let(:window_end) { '2073-09-05T23:00:00.000Z' }
|
22
|
+
let(:maintenance_dbs) do
|
23
|
+
[
|
24
|
+
[staging, 'staging-redis-db', [window_start, window_end]],
|
25
|
+
[staging, 'staging-postgres-db', nil],
|
26
|
+
[prod, 'prod-elsearch-db', [window_start, window_end]],
|
27
|
+
[prod, 'prod-postgres-db', nil]
|
28
|
+
].map do |a, h, m|
|
29
|
+
Fabricate(
|
30
|
+
:maintenance_database,
|
31
|
+
account: a,
|
32
|
+
handle: h,
|
33
|
+
maintenance_deadline: m
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
let(:maintenance_apps) do
|
38
|
+
[
|
39
|
+
[staging, 'staging-app-1', [window_start, window_end]],
|
40
|
+
[staging, 'staging-app-2', nil],
|
41
|
+
[prod, 'prod-app-1', [window_start, window_end]],
|
42
|
+
[prod, 'prod-app-2', nil]
|
43
|
+
].map do |a, h, m|
|
44
|
+
Fabricate(
|
45
|
+
:maintenance_app,
|
46
|
+
account: a,
|
47
|
+
handle: h,
|
48
|
+
maintenance_deadline: m
|
49
|
+
)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#maintenance:dbs' do
|
54
|
+
before do
|
55
|
+
token = 'the-token'
|
56
|
+
allow(subject).to receive(:fetch_token) { token }
|
57
|
+
allow(Aptible::Api::Account).to receive(:all)
|
58
|
+
.with(token: token)
|
59
|
+
.and_return([staging, prod])
|
60
|
+
allow(Aptible::Api::MaintenanceDatabase).to receive(:all)
|
61
|
+
.with(token: token)
|
62
|
+
.and_return(maintenance_dbs)
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when no account is specified' do
|
66
|
+
it 'prints out the grouped database handles for all accounts' do
|
67
|
+
subject.send('maintenance:dbs')
|
68
|
+
|
69
|
+
expect(captured_output_text).to include('=== staging')
|
70
|
+
expect(captured_output_text).to include('staging-redis-db')
|
71
|
+
expect(captured_output_text).to include('2073-09-05 22:00:00 UTC')
|
72
|
+
expect(captured_output_text).to include('2073-09-05 23:00:00 UTC')
|
73
|
+
expect(captured_output_text).not_to include('staging-postgres-db')
|
74
|
+
|
75
|
+
expect(captured_output_text).to include('=== production')
|
76
|
+
expect(captured_output_text).to include('prod-elsearch-db')
|
77
|
+
expect(captured_output_text).to include('2073-09-05 22:00:00 UTC')
|
78
|
+
expect(captured_output_text).to include('2073-09-05 23:00:00 UTC')
|
79
|
+
expect(captured_output_text).not_to include('prod-postgres-db')
|
80
|
+
|
81
|
+
expect(captured_output_json.to_s)
|
82
|
+
.to include(
|
83
|
+
'aptible db:restart staging-redis-db --environment staging'
|
84
|
+
)
|
85
|
+
expect(captured_output_json.to_s)
|
86
|
+
.to include(
|
87
|
+
'aptible db:restart prod-elsearch-db --environment production'
|
88
|
+
)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when a valid account is specified' do
|
93
|
+
it 'prints out the database handles for the account' do
|
94
|
+
subject.options = { environment: 'staging' }
|
95
|
+
subject.send('maintenance:dbs')
|
96
|
+
|
97
|
+
expect(captured_output_text).to include('=== staging')
|
98
|
+
expect(captured_output_text).to include('staging-redis-db')
|
99
|
+
expect(captured_output_text).to include('2073-09-05 22:00:00 UTC')
|
100
|
+
expect(captured_output_text).to include('2073-09-05 23:00:00 UTC')
|
101
|
+
expect(captured_output_text).not_to include('staging-postgres-db')
|
102
|
+
|
103
|
+
expect(captured_output_text).not_to include('=== production')
|
104
|
+
expect(captured_output_text).not_to include('prod-elsearch-db')
|
105
|
+
expect(captured_output_text).not_to include('prod-postgres-db')
|
106
|
+
|
107
|
+
expect(captured_output_json.to_s)
|
108
|
+
.to include(
|
109
|
+
'aptible db:restart staging-redis-db --environment staging'
|
110
|
+
)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'when an invalid account is specified' do
|
115
|
+
it 'prints out an error' do
|
116
|
+
subject.options = { environment: 'foo' }
|
117
|
+
expect { subject.send('maintenance:dbs') }
|
118
|
+
.to raise_error('Specified account does not exist')
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
describe '#maintenance:apps' do
|
123
|
+
before do
|
124
|
+
token = 'the-token'
|
125
|
+
allow(subject).to receive(:fetch_token) { token }
|
126
|
+
allow(Aptible::Api::Account).to receive(:all).with(token: token)
|
127
|
+
.and_return([staging, prod])
|
128
|
+
allow(Aptible::Api::MaintenanceApp).to receive(:all).with(token: token)
|
129
|
+
.and_return(maintenance_apps)
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'when no account is specified' do
|
133
|
+
it 'prints out the grouped app handles for all accounts' do
|
134
|
+
subject.send('maintenance:apps')
|
135
|
+
|
136
|
+
expect(captured_output_text).to include('=== staging')
|
137
|
+
expect(captured_output_text).to include('staging-app-1')
|
138
|
+
expect(captured_output_text).to include('2073-09-05 22:00:00 UTC')
|
139
|
+
expect(captured_output_text).to include('2073-09-05 23:00:00 UTC')
|
140
|
+
expect(captured_output_text).not_to include('staging-app-2')
|
141
|
+
|
142
|
+
expect(captured_output_text).to include('=== production')
|
143
|
+
expect(captured_output_text).to include('prod-app-1')
|
144
|
+
expect(captured_output_text).to include('2073-09-05 22:00:00 UTC')
|
145
|
+
expect(captured_output_text).to include('2073-09-05 23:00:00 UTC')
|
146
|
+
expect(captured_output_text).not_to include('prod-app-2')
|
147
|
+
|
148
|
+
expect(captured_output_json.to_s)
|
149
|
+
.to include(
|
150
|
+
'aptible restart --app staging-app-1 --environment staging'
|
151
|
+
)
|
152
|
+
expect(captured_output_json.to_s)
|
153
|
+
.to include(
|
154
|
+
'aptible restart --app prod-app-1 --environment production'
|
155
|
+
)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'when a valid account is specified' do
|
160
|
+
it 'prints out the app handles for the account' do
|
161
|
+
subject.options = { environment: 'staging' }
|
162
|
+
subject.send('maintenance:apps')
|
163
|
+
|
164
|
+
expect(captured_output_text).to include('=== staging')
|
165
|
+
expect(captured_output_text).to include('staging-app-1')
|
166
|
+
expect(captured_output_text).to include('2073-09-05 22:00:00 UTC')
|
167
|
+
expect(captured_output_text).to include('2073-09-05 23:00:00 UTC')
|
168
|
+
expect(captured_output_text).not_to include('staging-app-2')
|
169
|
+
|
170
|
+
expect(captured_output_text).not_to include('=== production')
|
171
|
+
expect(captured_output_text).not_to include('prod-app-1')
|
172
|
+
expect(captured_output_text).not_to include('prod-app-2')
|
173
|
+
|
174
|
+
expect(captured_output_json.to_s)
|
175
|
+
.to include(
|
176
|
+
'aptible restart --app staging-app-1 --environment staging'
|
177
|
+
)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context 'when an invalid account is specified' do
|
182
|
+
it 'prints out an error' do
|
183
|
+
subject.options = { environment: 'foo' }
|
184
|
+
expect { subject.send('maintenance:apps') }
|
185
|
+
.to raise_error('Specified account does not exist')
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
@@ -86,7 +86,7 @@ describe Aptible::CLI::Agent do
|
|
86
86
|
end
|
87
87
|
|
88
88
|
context 'influxdb:custom' do
|
89
|
-
it 'creates a new InfluxDB metric drain' do
|
89
|
+
it 'creates a new InfluxDB v1 metric drain' do
|
90
90
|
opts = {
|
91
91
|
handle: 'test-influxdb-custom',
|
92
92
|
drain_type: :influxdb,
|
@@ -111,6 +111,32 @@ describe Aptible::CLI::Agent do
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
+
context 'influxdb:customv2' do
|
115
|
+
it 'creates a new InfluxDB v2 metric drain' do
|
116
|
+
opts = {
|
117
|
+
handle: 'test-influxdb2-custom',
|
118
|
+
drain_type: :influxdb2,
|
119
|
+
drain_configuration: {
|
120
|
+
address: 'https://test.foo.com:443',
|
121
|
+
org: 'foobar',
|
122
|
+
authToken: 'bar',
|
123
|
+
bucket: 'foo'
|
124
|
+
}
|
125
|
+
}
|
126
|
+
expect_provision_metric_drain(opts)
|
127
|
+
|
128
|
+
subject.options = {
|
129
|
+
environment: account.handle,
|
130
|
+
bucket: 'foo',
|
131
|
+
token: 'bar',
|
132
|
+
org: 'foobar',
|
133
|
+
url: 'https://test.foo.com:443'
|
134
|
+
}
|
135
|
+
subject.send('metric_drain:create:influxdb:customv2',
|
136
|
+
'test-influxdb2-custom')
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
114
140
|
context 'datadog' do
|
115
141
|
it 'creates a new Datadog metric drain' do
|
116
142
|
opts = {
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class StubMaintenanceApp < OpenStruct; end
|
2
|
+
|
3
|
+
Fabricator(:maintenance_app, from: :stub_maintenance_app) do
|
4
|
+
id { Fabricate.sequence(:app_id) { |i| i } }
|
5
|
+
handle 'hello'
|
6
|
+
status 'provisioned'
|
7
|
+
account
|
8
|
+
created_at { Time.now }
|
9
|
+
maintenance_deadline { [Time.now + 1.minute, Time.now + 2.minute] }
|
10
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class StubMaintenanceDatabase < OpenStruct; end
|
2
|
+
|
3
|
+
Fabricator(:maintenance_database, from: :stub_maintenance_database) do
|
4
|
+
id { Fabricate.sequence(:database_id) { |i| i } }
|
5
|
+
handle 'hello'
|
6
|
+
status 'provisioned'
|
7
|
+
account
|
8
|
+
created_at { Time.now }
|
9
|
+
maintenance_deadline { [Time.now + 1.minute, Time.now + 2.minute] }
|
10
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aptible-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.19.
|
4
|
+
version: 0.19.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Frank Macreery
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-05-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aptible-resource
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
33
|
+
version: '1.4'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
40
|
+
version: '1.4'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: aptible-auth
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,6 +150,20 @@ dependencies:
|
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '2.0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: bigdecimal
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 1.3.5
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: 1.3.5
|
153
167
|
- !ruby/object:Gem::Dependency
|
154
168
|
name: activesupport
|
155
169
|
requirement: !ruby/object:Gem::Requirement
|
@@ -284,9 +298,11 @@ files:
|
|
284
298
|
- LICENSE.md
|
285
299
|
- README.md
|
286
300
|
- Rakefile
|
301
|
+
- SECURITY.md
|
287
302
|
- appveyor.yml
|
288
303
|
- aptible-cli.gemspec
|
289
304
|
- bin/aptible
|
305
|
+
- cleanup_bundler
|
290
306
|
- codecov.yml
|
291
307
|
- lib/aptible/cli.rb
|
292
308
|
- lib/aptible/cli/agent.rb
|
@@ -304,8 +320,10 @@ files:
|
|
304
320
|
- lib/aptible/cli/helpers/app_or_database.rb
|
305
321
|
- lib/aptible/cli/helpers/config_path.rb
|
306
322
|
- lib/aptible/cli/helpers/database.rb
|
323
|
+
- lib/aptible/cli/helpers/date_helpers.rb
|
307
324
|
- lib/aptible/cli/helpers/environment.rb
|
308
325
|
- lib/aptible/cli/helpers/log_drain.rb
|
326
|
+
- lib/aptible/cli/helpers/maintenance.rb
|
309
327
|
- lib/aptible/cli/helpers/metric_drain.rb
|
310
328
|
- lib/aptible/cli/helpers/operation.rb
|
311
329
|
- lib/aptible/cli/helpers/s3_log_helpers.rb
|
@@ -331,6 +349,7 @@ files:
|
|
331
349
|
- lib/aptible/cli/subcommands/inspect.rb
|
332
350
|
- lib/aptible/cli/subcommands/log_drain.rb
|
333
351
|
- lib/aptible/cli/subcommands/logs.rb
|
352
|
+
- lib/aptible/cli/subcommands/maintenance.rb
|
334
353
|
- lib/aptible/cli/subcommands/metric_drain.rb
|
335
354
|
- lib/aptible/cli/subcommands/operation.rb
|
336
355
|
- lib/aptible/cli/subcommands/rebuild.rb
|
@@ -342,6 +361,7 @@ files:
|
|
342
361
|
- spec/aptible/cli/agent_spec.rb
|
343
362
|
- spec/aptible/cli/formatter_spec.rb
|
344
363
|
- spec/aptible/cli/helpers/database_spec.rb
|
364
|
+
- spec/aptible/cli/helpers/date_helpers_spec.rb
|
345
365
|
- spec/aptible/cli/helpers/git_remote_handle_strategy_spec.rb
|
346
366
|
- spec/aptible/cli/helpers/handle_from_git_remote_spec.rb
|
347
367
|
- spec/aptible/cli/helpers/operation_spec.rb
|
@@ -363,6 +383,7 @@ files:
|
|
363
383
|
- spec/aptible/cli/subcommands/inspect_spec.rb
|
364
384
|
- spec/aptible/cli/subcommands/log_drain_spec.rb
|
365
385
|
- spec/aptible/cli/subcommands/logs_spec.rb
|
386
|
+
- spec/aptible/cli/subcommands/maintenance_spec.rb
|
366
387
|
- spec/aptible/cli/subcommands/metric_drain_spec.rb
|
367
388
|
- spec/aptible/cli/subcommands/operation_spec.rb
|
368
389
|
- spec/aptible/cli/subcommands/rebuild_spec.rb
|
@@ -380,6 +401,8 @@ files:
|
|
380
401
|
- spec/fabricators/database_fabricator.rb
|
381
402
|
- spec/fabricators/database_image_fabricator.rb
|
382
403
|
- spec/fabricators/log_drain_fabricator.rb
|
404
|
+
- spec/fabricators/maintenance_app_fabricator.rb
|
405
|
+
- spec/fabricators/maintenance_database_fabricator.rb
|
383
406
|
- spec/fabricators/metric_drain_fabricator.rb
|
384
407
|
- spec/fabricators/operation_fabricator.rb
|
385
408
|
- spec/fabricators/service_fabricator.rb
|
@@ -414,7 +437,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
414
437
|
- !ruby/object:Gem::Version
|
415
438
|
version: '0'
|
416
439
|
requirements: []
|
417
|
-
rubygems_version: 3.
|
440
|
+
rubygems_version: 3.1.6
|
418
441
|
signing_key:
|
419
442
|
specification_version: 4
|
420
443
|
summary: Command-line interface for Aptible services
|
@@ -422,6 +445,7 @@ test_files:
|
|
422
445
|
- spec/aptible/cli/agent_spec.rb
|
423
446
|
- spec/aptible/cli/formatter_spec.rb
|
424
447
|
- spec/aptible/cli/helpers/database_spec.rb
|
448
|
+
- spec/aptible/cli/helpers/date_helpers_spec.rb
|
425
449
|
- spec/aptible/cli/helpers/git_remote_handle_strategy_spec.rb
|
426
450
|
- spec/aptible/cli/helpers/handle_from_git_remote_spec.rb
|
427
451
|
- spec/aptible/cli/helpers/operation_spec.rb
|
@@ -443,6 +467,7 @@ test_files:
|
|
443
467
|
- spec/aptible/cli/subcommands/inspect_spec.rb
|
444
468
|
- spec/aptible/cli/subcommands/log_drain_spec.rb
|
445
469
|
- spec/aptible/cli/subcommands/logs_spec.rb
|
470
|
+
- spec/aptible/cli/subcommands/maintenance_spec.rb
|
446
471
|
- spec/aptible/cli/subcommands/metric_drain_spec.rb
|
447
472
|
- spec/aptible/cli/subcommands/operation_spec.rb
|
448
473
|
- spec/aptible/cli/subcommands/rebuild_spec.rb
|
@@ -460,6 +485,8 @@ test_files:
|
|
460
485
|
- spec/fabricators/database_fabricator.rb
|
461
486
|
- spec/fabricators/database_image_fabricator.rb
|
462
487
|
- spec/fabricators/log_drain_fabricator.rb
|
488
|
+
- spec/fabricators/maintenance_app_fabricator.rb
|
489
|
+
- spec/fabricators/maintenance_database_fabricator.rb
|
463
490
|
- spec/fabricators/metric_drain_fabricator.rb
|
464
491
|
- spec/fabricators/operation_fabricator.rb
|
465
492
|
- spec/fabricators/service_fabricator.rb
|