enviroblyd 0.3 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b81310d8a36d3cb1cf6f6c52d106cc956efda2aa46a88e82f62faa4d350abf6
4
- data.tar.gz: c7bb64bff1ba36ba7bdbc3c9ebdc759a452242787d5b77876f8b5bc5aa5fb853
3
+ metadata.gz: 5bfe5d8525ca24df27fe3c85f2715a6dc74d9bd931aff02c1a1c96c79b4b8c98
4
+ data.tar.gz: cb67d4b4c55e328c63e85ad6a976b24fd29e7517ec5de154ae613fe2712a7ec8
5
5
  SHA512:
6
- metadata.gz: c529bc70a326723e8ca8ab18eda6207e06a9b272ba75e06cdb01746c451009d991fedc77647d17dfa787016a5a9bf8cde1d77f45080ac4a7b707bc477a7cf3e0
7
- data.tar.gz: aa5e7808630a375aa4dffeda5ca67c4c1866f8cf3577db35be27d22b50f3d7854b78499c9f35256c6079916ff49fc0c81a9a565d60b160d3bb8d9c586b6b9171
6
+ metadata.gz: 30ce5bcada6cd8abdfc0ab7f8cf58e15b3670f55f659d2b40bec9ef75e502ca8e65fbd6ab7e13fc42ec5d7cae362522f1e82645a746b24f7fb8ba2218677029e
7
+ data.tar.gz: 6125a642bc7ecad4db9ea7c50f2039584a7f7ddccd4a1f41663bff22318149c78333bd936cf5d023e5e409b69beebd71ea854919b89cc479ca93c12587943c15
data/bin/enviroblyctl ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "enviroblyd"
5
+
6
+ Enviroblyd::Cli::Main.start(ARGV)
data/bin/enviroblyd CHANGED
@@ -3,4 +3,4 @@
3
3
 
4
4
  require "enviroblyd"
5
5
 
6
- Enviroblyd::Cli::Main.start(ARGV)
6
+ Enviroblyd::Daemon.start
@@ -1,95 +1,8 @@
1
1
  # frozen_string_literal: true
2
- require "net/http"
3
- require "uri"
4
- require "open3"
5
2
 
6
3
  class Enviroblyd::Cli::Main < Enviroblyd::Base
7
4
  desc "version", "Show version"
8
5
  def version
9
6
  puts Enviroblyd::VERSION
10
7
  end
11
-
12
- TOKEN_TTL_SECONDS = 30
13
- IMDS_HOST = ENV.fetch("ENVIROBLYD_IMDS_HOST", "169.254.169.254")
14
- API_HOST = ENV.fetch("ENVIROBLYD_API_HOST", "envirobly.com")
15
- desc "boot", "Get IMDSv2 metadata"
16
- def boot
17
- @token = http("http://#{IMDS_HOST}/latest/api/token",
18
- type: Net::HTTP::Put, headers: { "X-aws-ec2-metadata-token-ttl-seconds" => TOKEN_TTL_SECONDS.to_s }).
19
- body.chomp("")
20
- puts "token: #{@token} ."
21
- instance_id = http("http://#{IMDS_HOST}/latest/meta-data/instance-id",
22
- headers: { "X-aws-ec2-metadata-token" => @token }).
23
- body.chomp("")
24
- puts "instance_id: #{instance_id} ."
25
-
26
- # process_user_data
27
- # unless @exit_code.nil?
28
- # puts @stdout
29
- # $stderr.puts @stderr
30
- # unless @exit_code == 0
31
- # $stderr.puts "User data script exited with code: #{@exit_code}. Aborting."
32
- # exit 1
33
- # end
34
- # end
35
-
36
- response = http("https://#{API_HOST}/api/v1/boots/#{instance_id}", retry_interval: 3, retries: 5, backoff: :exponential)
37
- puts "/api/v1/boots response code: #{response.code}"
38
- end
39
-
40
- private
41
- def http(url, type: Net::HTTP::Get, headers: {}, retry_interval: 2, retries: 30, backoff: false, success_codes: 200..299, tries: 1)
42
- uri = URI(url)
43
- http = Net::HTTP.new uri.host, uri.port
44
- http.use_ssl = true if uri.scheme == "https"
45
- http.open_timeout = 5
46
- http.read_timeout = 5
47
-
48
- request = type.new(uri, headers)
49
- # request.content_type = CONTENT_TYPE
50
-
51
- yield request if block_given?
52
-
53
- response =
54
- begin
55
- http.request(request)
56
- rescue
57
- nil
58
- end
59
-
60
- if response && success_codes.include?(response.code.to_i)
61
- response
62
- elsif retries <= tries
63
- $stderr.puts "Retried #{tries} times. Aborting."
64
- exit 1
65
- else
66
- sleep_time = (backoff == :exponential) ? (retry_interval * tries) : retry_interval
67
- $stderr.puts "Retry #{uri} in #{sleep_time}s"
68
- sleep sleep_time
69
- http(url, type:, retry_interval:, retries:, backoff:, success_codes:, tries: (tries + 1))
70
- end
71
- end
72
-
73
- def process_user_data
74
- response = http("http://#{IMDS_HOST}/latest/user-data",
75
- headers: { "X-aws-ec2-metadata-token" => @token })
76
-
77
- if response.body.start_with?("#!/bin/bash")
78
- run response.body
79
- else
80
- $stderr.puts "User data does not contain runable script."
81
- end
82
- end
83
-
84
- RUN_TIMEOUT = "5m"
85
- def run(script)
86
- @stdout = @stderr = @exit_code = nil
87
- Open3.popen3("timeout #{RUN_TIMEOUT} /bin/bash") do |stdin, stdout, stderr, thread|
88
- stdin.puts script
89
- stdin.close
90
- @stdout = stdout.read
91
- @stderr = stderr.read
92
- @exit_code = thread.value.exitstatus
93
- end
94
- end
95
8
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+
5
+ class Enviroblyd::Command
6
+ DEFAULT_TIMEOUT_SECONDS = 5 * 60
7
+ DEFAULT_RUNTIME = "/bin/bash"
8
+
9
+ def initialize(params)
10
+ @web = Enviroblyd::Web.new
11
+ @url = params.fetch "url"
12
+ @script = params.fetch "script"
13
+ @runtime = params.fetch "runtime", DEFAULT_RUNTIME
14
+ @timeout = params.fetch "timeout", DEFAULT_TIMEOUT_SECONDS
15
+ @stdout = @stderr = @exit_code = nil
16
+ end
17
+
18
+ def run
19
+ puts "Command #{@url} starting"
20
+
21
+ Open3.popen3("timeout #{@timeout} #{@runtime}") do |stdin, stdout, stderr, thread|
22
+ stdin.puts @script
23
+ stdin.close
24
+ @stdout = stdout.read
25
+ @stderr = stderr.read
26
+ @exit_code = thread.value.exitstatus
27
+ end
28
+
29
+ puts "Command #{@url} exited with #{@exit_code}"
30
+
31
+ @web.http(@url, type: Net::HTTP::Put, params: to_complete_params)
32
+ end
33
+
34
+ private
35
+ def to_complete_params
36
+ {
37
+ command: {
38
+ stdout: @stdout,
39
+ stderr: @stderr,
40
+ exit_code: @exit_code
41
+ }
42
+ }
43
+ end
44
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "socket"
4
+ require "json"
5
+
6
+ class Enviroblyd::Daemon
7
+ MAX_MESSAGE_SIZE = 6000 # bytes
8
+ LISTEN_PORT = ENV.fetch("ENVIROBLYD_PORT", 63106).to_i
9
+
10
+ def self.start
11
+ web = Enviroblyd::Web.new
12
+ web.register
13
+
14
+ daemon = new
15
+ daemon.listen
16
+ end
17
+
18
+ def listen
19
+ server = TCPServer.new LISTEN_PORT
20
+ puts "Listening on port #{LISTEN_PORT}"
21
+
22
+ loop do
23
+ Thread.start(server.accept) do |client|
24
+ message = client.recv(MAX_MESSAGE_SIZE)
25
+
26
+ params =
27
+ begin
28
+ JSON.parse message
29
+ rescue
30
+ nil
31
+ end
32
+
33
+ if params.nil?
34
+ client.puts "Error parsing JSON"
35
+ else
36
+ puts "Received valid JSON:"
37
+ puts params
38
+ client.puts "OK"
39
+ end
40
+
41
+ # TODO: Handle Broken pipe (Errno::EPIPE) (client closing connection before we write back)
42
+ client.close
43
+
44
+ Thread.new do
45
+ Enviroblyd::Command.new(params).run
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Enviroblyd
4
- VERSION = "0.3"
4
+ VERSION = "0.4"
5
5
  end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "uri"
5
+ require "open3"
6
+ require "fileutils"
7
+ require "pathname"
8
+ require "json"
9
+
10
+ class Enviroblyd::Web
11
+ USER_AGENT = "enviroblyd #{Enviroblyd::VERSION}"
12
+ CONTENT_TYPE = "application/json"
13
+ # TOKEN_TTL_SECONDS = 30
14
+ # IMDS_HOST = ENV.fetch("ENVIROBLYD_IMDS_HOST", "169.254.169.254")
15
+ API_HOST = ENV.fetch("ENVIROBLYD_API_HOST", "envirobly.com")
16
+ WORKING_DIR = Pathname.new ENV.fetch("ENVIROBLYD_WORKING_DIR", "/var/envirobly/daemon")
17
+ INITIALIZED_FILE = WORKING_DIR.join "initialized"
18
+
19
+ def register
20
+ if File.exist?(INITIALIZED_FILE)
21
+ puts "Skipping initialization because #{INITIALIZED_FILE} exists."
22
+ else
23
+ init_url = ENV.fetch "ENVIROBLYD_INIT_URL"
24
+ puts "Init URL: #{init_url}"
25
+ response = http(init_url, type: Net::HTTP::Put, retry_interval: 3, retries: 10, backoff: :exponential)
26
+ puts "Init response code: #{response.code}"
27
+
28
+ if response.code.to_i == 200
29
+ FileUtils.mkdir_p WORKING_DIR
30
+ File.write INITIALIZED_FILE, init_url
31
+ end
32
+ end
33
+ end
34
+
35
+ def http(url, type: Net::HTTP::Get, headers: {}, retry_interval: 2, retries: 30, backoff: false, tries: 1, params: nil)
36
+ if retries <= tries
37
+ $stderr.puts "Retried #{tries} times. Aborting."
38
+ exit 1
39
+ end
40
+
41
+ uri = URI(url)
42
+ http = Net::HTTP.new uri.host, uri.port
43
+ http.use_ssl = true if uri.scheme == "https"
44
+ http.open_timeout = 5
45
+ http.read_timeout = 5
46
+
47
+ request = type.new(uri, default_headers.merge(headers))
48
+ request.content_type = CONTENT_TYPE
49
+
50
+ unless params.nil?
51
+ request.body = JSON.dump params
52
+ end
53
+
54
+ response =
55
+ begin
56
+ http.request(request)
57
+ rescue
58
+ :retry
59
+ end
60
+
61
+ # https://developers.cloudflare.com/support/troubleshooting/cloudflare-errors/troubleshooting-cloudflare-1xxx-errors/
62
+ if response == :retry || (500..599).include?(response.code.to_i)
63
+ sleep_time = (backoff == :exponential) ? (retry_interval * tries) : retry_interval
64
+ $stderr.puts "Retry #{uri} in #{sleep_time}s"
65
+ sleep sleep_time
66
+ http(url, type:, retry_interval:, retries:, backoff:, tries: (tries + 1))
67
+ else
68
+ response
69
+ end
70
+ end
71
+
72
+ private
73
+ def default_headers
74
+ { "User-Agent" => USER_AGENT }
75
+ end
76
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enviroblyd
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.3'
4
+ version: '0.4'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Starsi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-03 00:00:00.000000000 Z
11
+ date: 2024-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -55,16 +55,21 @@ dependencies:
55
55
  description:
56
56
  email: klevo@klevo.sk
57
57
  executables:
58
+ - enviroblyctl
58
59
  - enviroblyd
59
60
  extensions: []
60
61
  extra_rdoc_files: []
61
62
  files:
62
63
  - LICENSE
64
+ - bin/enviroblyctl
63
65
  - bin/enviroblyd
64
66
  - lib/enviroblyd.rb
65
67
  - lib/enviroblyd/base.rb
66
68
  - lib/enviroblyd/cli/main.rb
69
+ - lib/enviroblyd/command.rb
70
+ - lib/enviroblyd/daemon.rb
67
71
  - lib/enviroblyd/version.rb
72
+ - lib/enviroblyd/web.rb
68
73
  homepage: https://github.com/envirobly/enviroblyd
69
74
  licenses:
70
75
  - MIT
@@ -84,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
89
  - !ruby/object:Gem::Version
85
90
  version: '0'
86
91
  requirements: []
87
- rubygems_version: 3.5.14
92
+ rubygems_version: 3.5.18
88
93
  signing_key:
89
94
  specification_version: 4
90
95
  summary: Envirobly instance daemon