firespring_dev_commands 2.1.26.pre.alpha.2 → 2.1.27.pre.alpha.2

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: b68163bb71bf29450c83939ecdc3181f8003ac39731839c0c67dd5808c2f9331
4
- data.tar.gz: c956a7f6c49ce1d0478df460e54d24a5c12598b4c24b905f959e489c289515f3
3
+ metadata.gz: fce5da47cf928179b220c2d30c295fb5c853aee03ca1cad7bbf9684f8b8aea3a
4
+ data.tar.gz: 33100d5b2127c7cb422f6695e19e85b3f8bfe41d0dd13f7f0ab4f4721351286b
5
5
  SHA512:
6
- metadata.gz: 7f62bd98a204af676eb9bec3cf64c4783c20ad265115df7fbf4e13964a5f5bd9ce3ceb89f3ecb505c478f06fcab1b7635814ebeb999e62e133c63728bf6d7f7e
7
- data.tar.gz: 92b52d27ab0b6a15ebdb16098296259010284326d20719d45d10b41d4f0e73801ec00b1a48ad7f7a0cd941db47b4541bbdad7024cf593aff403324791908a8bb
6
+ metadata.gz: fb735b569248c55a15bd51bb971054107ea1d885fb08e4a2da43bafdc3093b86daf00c42962fcb0ce4aeb543e76afff8ca06be4359bbbd4c489dc83c09d46bc6
7
+ data.tar.gz: 4e43a5eee15f6dbbbeab27c006a0dbdb1802be2c882008627b4d1025f99e72a52d3855c8121eba967b21fba4f766daf1e2f0e90e11bb06ab32f7c6e110f86d7e
@@ -0,0 +1,59 @@
1
+ module Dev
2
+ # Class contains methods for requesting a certificate from route53.
3
+ # You must have a hosted zone defined for the desired domain
4
+ class Certificate
5
+ attr_accessor :domains, :email
6
+
7
+ def initialize(domains, email)
8
+ @domains = Array(domains)
9
+ @email = email
10
+ raise 'No certificate domains specified' if domains.empty?
11
+ end
12
+
13
+ # Request the certificate using the route53 docker image
14
+ # Certificate is stored in /etc/letsencrypt
15
+ def request
16
+ puts
17
+ puts 'Getting SSL Certs For:'
18
+ puts domains.join("\n")
19
+ puts
20
+ puts 'This process can take up to 10 minutes'
21
+ puts
22
+ puts Time.now
23
+
24
+ # TODO: Really should use the docker api for this
25
+ cmd = %w(docker run -it --rm --name certbot)
26
+ cmd << '-e' << 'AWS_ACCESS_KEY_ID'
27
+ cmd << '-e' << 'AWS_SECRET_ACCESS_KEY'
28
+ cmd << '-e' << 'AWS_SESSION_TOKEN'
29
+ cmd << '-v' << '/etc/letsencrypt:/etc/letsencrypt'
30
+ cmd << 'certbot/dns-route53:latest'
31
+ cmd << 'certonly'
32
+ cmd << '-n'
33
+ cmd << '--agree-tos'
34
+ cmd << '--dns-route53'
35
+ cmd << '-d' << domains.join(',')
36
+ cmd << '--email' << email
37
+ cmd << '--server' << 'https://acme-v02.api.letsencrypt.org/directory'
38
+ puts cmd.join(' ')
39
+ Dev::Common.new.run_command(cmd)
40
+ end
41
+
42
+ # Saves the latest version of the certificate into the given dest_dir
43
+ def save(dest_dir)
44
+ raise "directory #{dest_dir} must be an existing directory" unless File.directory?(dest_dir)
45
+
46
+ domain = domains.first.sub(/^\*\./, '') # Need to strip off the '*.' if this is a wildcard cert
47
+ directories = Dir.glob("/etc/letsencrypt/live/#{domain}*/")
48
+ no_suffix = directories.delete("/etc/letsencrypt/live/#{domain}/")
49
+ biggest_suffix = directories.max
50
+ source_dir = biggest_suffix || no_suffix
51
+ raise "unable to determine certificate directory for #{domain}" unless source_dir
52
+
53
+ FileUtils.cp("#{source_dir}privkey.pem", dest_dir, verbose: true)
54
+ FileUtils.cp("#{source_dir}cert.pem", dest_dir, verbose: true)
55
+ FileUtils.cp("#{source_dir}chain.pem", dest_dir, verbose: true)
56
+ FileUtils.cp("#{source_dir}fullchain.pem", dest_dir, verbose: true)
57
+ end
58
+ end
59
+ end
@@ -33,6 +33,26 @@ module Dev
33
33
  EXITED,
34
34
  DEAD
35
35
  ].freeze
36
+
37
+ # TODO: Can we use 'curses' here and overwrite the correct line?
38
+ def response_callback(response)
39
+ response.split("\n").each do |line|
40
+ data = JSON.parse(line)
41
+ if data.include?('status')
42
+ if data['id']
43
+ LOG.info "#{data['id']}: #{data['status']}"
44
+ else
45
+ LOG.info (data['status']).to_s
46
+ end
47
+ elsif data.include?('errorDetail')
48
+ raise data['errorDetail']['message']
49
+ elsif data.include?('aux')
50
+ next
51
+ else
52
+ raise "Unrecognized message from docker: #{data}"
53
+ end
54
+ end
55
+ end
36
56
  end
37
57
  end
38
58
  end
@@ -117,6 +117,44 @@ module Dev
117
117
  format('%.1f %s', size.to_f / (1024**exp), units[exp])
118
118
  end
119
119
 
120
+ # Push the local version of the docker image to the defined remote repository
121
+ def push_image(image, name, tag = nil)
122
+ unless tag
123
+ if name.include?(':')
124
+ name, tag = name.split(':')
125
+ else
126
+ tag = 'latest'
127
+ end
128
+ end
129
+
130
+ puts "Pushing to #{name}:#{tag}"
131
+ image.push(::Docker.creds, repo_tag: "#{name}:#{tag}") { |response| Dev::Docker::Status.new.response_callback(response) }
132
+ end
133
+
134
+ # Push the remote version of the docker image from the defined remote repository
135
+ def pull_image(name, tag = nil)
136
+ unless tag
137
+ if name.include?(':')
138
+ name, tag = name.split(':')
139
+ else
140
+ tag = 'latest'
141
+ end
142
+ end
143
+
144
+ puts "\nPulling #{name}:#{tag}"
145
+ opts = {
146
+ fromImage: "#{name}:#{tag}",
147
+ platform: Dev::Platform.new.architecture
148
+ }
149
+ ::Docker::Image.create(**opts) { |response| Dev::Docker::Status.new.response_callback(response) }
150
+ end
151
+
152
+ # Remove the local version of the given docker image
153
+ def untag_image(image, name, tag)
154
+ puts "Untagging #{name}:#{tag}"
155
+ image.remove(name: "#{name}:#{tag}")
156
+ end
157
+
120
158
  # Remove docker images with the "force" option set to true
121
159
  # This will remove the images even if they are currently in use and cause unintended side effects.
122
160
  def force_remove_images(name_and_tag)
@@ -5,9 +5,8 @@ module Dev
5
5
  END_OF_LIFE_API_URL = 'https://endoflife.date/api'.freeze
6
6
 
7
7
  # Config object for setting top level git config options
8
- Config = Struct.new(:check_aws_resources, :product_versions, :manual_dates) do
8
+ Config = Struct.new(:product_versions, :manual_dates) do
9
9
  def initialize
10
- self.check_aws_resources = false
11
10
  self.product_versions = []
12
11
  self.manual_dates = {}
13
12
  end
@@ -27,10 +26,9 @@ module Dev
27
26
  alias_method :configure, :config
28
27
  end
29
28
 
30
- attr_accessor :url, :products, :check_aws_resources, :product_versions
29
+ attr_accessor :url, :products, :product_versions
31
30
 
32
- def initialize(check_aws_resources: self.class.config.check_aws_resources, product_versions: self.class.config.product_versions)
33
- @check_aws_resources = check_aws_resources
31
+ def initialize(product_versions: self.class.config.product_versions)
34
32
  @product_versions = Array(product_versions)
35
33
  raise 'product version must be of type Dev::EndOfLife::ProductVersions' unless @product_versions.all?(Dev::EndOfLife::ProductVersion)
36
34
  end
@@ -52,14 +50,7 @@ module Dev
52
50
  # Raises an error if any products are EOL
53
51
  def check
54
52
  puts
55
- checks_to_perform = product_versions.clone
56
- if check_aws_resources
57
- account_id = Dev::Aws::Profile.new.current
58
- account_name = Dev::Aws::Account.new.name_by_account(account_id)
59
- LOG.info " Current AWS Account is #{account_name} (#{account_id})\n".light_yellow
60
- checks_to_perform.concat(Dev::EndOfLife::Aws.new.default_products)
61
- end
62
- checks_to_perform.sort_by(&:name).each(&:print_status)
53
+ product_versions.sort_by(&:name).each(&:print_status)
63
54
  puts
64
55
  raise 'found EOL versions' if product_versions.any?(&:eol)
65
56
  end
@@ -1,40 +1,33 @@
1
1
  module Dev
2
- class Common
3
- # Class which returns information about the current platform
4
- class Platform
5
- # Constant containing all supported architectures
6
- ALLOWED_ARCHITECTURES = %w(arm64 amd64).freeze
2
+ # Class which returns information about the current platform
3
+ class Platform
4
+ # Constant containing all supported architectures
5
+ ALLOWED_ARCHITECTURES = %w(linux/arm64 linux/amd64).freeze
7
6
 
8
- # Normalize the ruby platform to return a docker platform architecture format
9
- def determine_compute_architecture
10
- case RUBY_PLATFORM
11
- when /x86_64|amd64|x64-mingw/
12
- 'linux/amd64' # 64-bit Intel/AMD architecture
13
- when /arm|aarch64/
14
- 'linux/arm64' # ARM architecture
15
- else
16
- raise 'Unknown or unsupported architecture'
17
- end
18
- end
7
+ # If an architecture was specified in the ENV, use that. Otherwise auto-deted based of the OS reported architecture
8
+ def architecture
9
+ arch = env_architecture || os_architecture
10
+ raise "Invalid DOCKER_ARCHITECTURE: #{arch} (allowed are #{ALLOWED_ARCHITECTURES.join(', ')})" unless ALLOWED_ARCHITECTURES.include?(arch)
19
11
 
20
- # Determine the platform architecture
21
- # If one was specified in the DOCKER_ARCHITECTURE variable, use it
22
- # Otherwise, use the RUBY_PLATFORM built-in to auto-detect and architecture
23
- def architecture
24
- docker_architecture = ENV['DOCKER_ARCHITECTURE'].to_s.strip.downcase
25
- if docker_architecture.empty?
26
- determine_compute_architecture
27
- else
28
- raise "Missing 'linux/' prefix in DOCKER_ARCHITECTURE: #{docker_architecture}" unless docker_architecture.start_with?('linux/')
12
+ arch
13
+ end
14
+
15
+ # Check to see if a docker architecture has been specified in the ENV
16
+ # If it has, verify the format and the value
17
+ private def env_architecture
18
+ arch = ENV['DOCKER_ARCHITECTURE'].to_s.strip.downcase
19
+ return nil if arch.empty?
20
+
21
+ "linux/#{arch}" unless arch.start_with?('linux/')
22
+ arch
23
+ end
29
24
 
30
- architecture_name = docker_architecture.split('/')[1]
31
- unless ALLOWED_ARCHITECTURES.include?(architecture_name)
32
- raise "Invalid DOCKER_ARCHITECTURE: #{architecture_name}. Allowed architectures are #{ALLOWED_ARCHITECTURES.join(', ')}"
33
- end
25
+ # Returns a valid docker architecture based off the RUBY_PLATFORM
26
+ private def os_architecture
27
+ return 'linux/amd64' if RUBY_PLATFORM.match?(/x86_64|amd64|x64-mingw/)
28
+ return 'linux/arm64' if RUBY_PLATFORM.match?(/arm|aarch64/)
34
29
 
35
- docker_architecture
36
- end
37
- end
30
+ raise 'Unknown or unsupported architecture'
38
31
  end
39
32
  end
40
33
  end
@@ -94,11 +94,23 @@ module Dev
94
94
  end
95
95
  # rubocop:enable Metrics/MethodLength
96
96
 
97
- # Set the EOL library to also check AWS resources
97
+ # Create the rake task for the eol method
98
98
  def create_eol_task!
99
- return if exclude.include?(:eol)
99
+ # Have to set a local variable to be accessible inside of the instance_eval block
100
+ exclude = @exclude
101
+
102
+ DEV_COMMANDS_TOP_LEVEL.instance_eval do
103
+ return if exclude.include?(:eol)
100
104
 
101
- Dev::EndOfLife.config { |c| c.check_aws_resources = true }
105
+ desc 'Compares the current date to the EOL date for supported resources'
106
+ task eol: %w(init ensure_aws_credentials) do
107
+ account_id = Dev::Aws::Profile.new.current
108
+ account_name = Dev::Aws::Account.new.name_by_account(account_id)
109
+ LOG.info " Current AWS Account is #{account_name} (#{account_id})".light_yellow
110
+
111
+ Dev::EndOfLife.new(product_versions: Dev::EndOfLife::Aws.new.default_products).check
112
+ end
113
+ end
102
114
  end
103
115
  end
104
116
  end
@@ -0,0 +1,41 @@
1
+ require_relative 'base_interface'
2
+
3
+ module Dev
4
+ module Template
5
+ # Class contains rake templates for managing configured certificates
6
+ class Certificate < Dev::Template::BaseInterface
7
+ attr_reader :domains, :email, :paths
8
+
9
+ def initialize(domains, email:, paths:, exclude: [])
10
+ @domains = domains
11
+ @email = email
12
+ @paths = Array(paths)
13
+
14
+ super(exclude:)
15
+ end
16
+
17
+ # Create the rake task for the generate method
18
+ def create_generate_task!
19
+ # Have to set a local variable to be accessible inside of the instance_eval block
20
+ domains = @domains
21
+ email = @email
22
+ paths = @paths
23
+ exclude = @exclude
24
+
25
+ DEV_COMMANDS_TOP_LEVEL.instance_eval do
26
+ return if exclude.include?(:generate)
27
+
28
+ namespace :certificate do
29
+ desc 'Requests a new certificate for the configured domain using the route53 validation and deposits it in the configured paths'
30
+ task generate: %w(init_docker ensure_aws_credentials) do
31
+ Dev::Docker.new.pull_image('certbot/dns-route53', 'latest')
32
+ c = Dev::Certificate.new(domains, email)
33
+ c.request
34
+ paths.each { |path| c.save(path) }
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -4,23 +4,6 @@ module Dev
4
4
  module Template
5
5
  # Class contains rake templates for managing your git project
6
6
  class Git < Dev::Template::BaseInterface
7
- # Create the rake task for cloning all defined repos
8
- def create_clone_task!
9
- # Have to set a local variable to be accessible inside of the instance_eval block
10
- exclude = @exclude
11
-
12
- DEV_COMMANDS_TOP_LEVEL.instance_eval do
13
- namespace :git do
14
- return if exclude.include?(:clone)
15
-
16
- desc 'Make sure all repos are cloned'
17
- task :clone do
18
- Dev::Git.new.clone_repos
19
- end
20
- end
21
- end
22
- end
23
-
24
7
  # Create the rake task for the git checkout method
25
8
  def create_checkout_task!
26
9
  # Have to set a local variable to be accessible inside of the instance_eval block
@@ -6,6 +6,6 @@ module Dev
6
6
  # Use 'v.v.v.pre.alpha.v' for pre-release vesions
7
7
  # Use 'v.v.v.beta.v for beta versions
8
8
  # Use semantic versioning for any releases (https://semver.org/)
9
- VERSION = '2.1.26.pre.alpha.2'.freeze
9
+ VERSION = '2.1.27.pre.alpha.2'.freeze
10
10
  end
11
11
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: firespring_dev_commands
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.26.pre.alpha.2
4
+ version: 2.1.27.pre.alpha.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Firespring
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-16 00:00:00.000000000 Z
11
+ date: 2024-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -332,6 +332,7 @@ files:
332
332
  - lib/firespring_dev_commands/bloom_growth/seat.rb
333
333
  - lib/firespring_dev_commands/bloom_growth/user.rb
334
334
  - lib/firespring_dev_commands/boolean.rb
335
+ - lib/firespring_dev_commands/certificate.rb
335
336
  - lib/firespring_dev_commands/common.rb
336
337
  - lib/firespring_dev_commands/coverage/base.rb
337
338
  - lib/firespring_dev_commands/coverage/cobertura.rb
@@ -383,6 +384,7 @@ files:
383
384
  - lib/firespring_dev_commands/target_process/user_story_history.rb
384
385
  - lib/firespring_dev_commands/templates/aws.rb
385
386
  - lib/firespring_dev_commands/templates/base_interface.rb
387
+ - lib/firespring_dev_commands/templates/certificate.rb
386
388
  - lib/firespring_dev_commands/templates/ci.rb
387
389
  - lib/firespring_dev_commands/templates/config.rb
388
390
  - lib/firespring_dev_commands/templates/docker/application.rb