latitude-api 0.2.0

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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +10 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +283 -0
  5. data/Rakefile +13 -0
  6. data/lib/latitude/api/api_object.rb +105 -0
  7. data/lib/latitude/api/api_resource.rb +260 -0
  8. data/lib/latitude/api/attributes.rb +64 -0
  9. data/lib/latitude/api/client.rb +80 -0
  10. data/lib/latitude/api/configuration.rb +88 -0
  11. data/lib/latitude/api/errors.rb +134 -0
  12. data/lib/latitude/api/json_api.rb +40 -0
  13. data/lib/latitude/api/list_object.rb +129 -0
  14. data/lib/latitude/api/objects.rb +216 -0
  15. data/lib/latitude/api/operations/action.rb +41 -0
  16. data/lib/latitude/api/operations/create.rb +22 -0
  17. data/lib/latitude/api/operations/delete.rb +22 -0
  18. data/lib/latitude/api/operations/list.rb +54 -0
  19. data/lib/latitude/api/operations/nested.rb +53 -0
  20. data/lib/latitude/api/operations/retrieve.rb +22 -0
  21. data/lib/latitude/api/operations/update.rb +22 -0
  22. data/lib/latitude/api/request_executor.rb +217 -0
  23. data/lib/latitude/api/request_options.rb +86 -0
  24. data/lib/latitude/api/request_params.rb +70 -0
  25. data/lib/latitude/api/resources/api_key.rb +61 -0
  26. data/lib/latitude/api/resources/billing_usage.rb +51 -0
  27. data/lib/latitude/api/resources/elastic_ip.rb +96 -0
  28. data/lib/latitude/api/resources/event.rb +55 -0
  29. data/lib/latitude/api/resources/firewall.rb +129 -0
  30. data/lib/latitude/api/resources/ip.rb +110 -0
  31. data/lib/latitude/api/resources/kubernetes_cluster.rb +184 -0
  32. data/lib/latitude/api/resources/plan.rb +658 -0
  33. data/lib/latitude/api/resources/project.rb +179 -0
  34. data/lib/latitude/api/resources/region.rb +41 -0
  35. data/lib/latitude/api/resources/role.rb +20 -0
  36. data/lib/latitude/api/resources/server.rb +251 -0
  37. data/lib/latitude/api/resources/ssh_key.rb +44 -0
  38. data/lib/latitude/api/resources/storage_filesystem.rb +36 -0
  39. data/lib/latitude/api/resources/storage_object.rb +85 -0
  40. data/lib/latitude/api/resources/storage_volume.rb +64 -0
  41. data/lib/latitude/api/resources/tag.rb +34 -0
  42. data/lib/latitude/api/resources/team.rb +169 -0
  43. data/lib/latitude/api/resources/traffic.rb +215 -0
  44. data/lib/latitude/api/resources/user_data.rb +38 -0
  45. data/lib/latitude/api/resources/user_profile.rb +51 -0
  46. data/lib/latitude/api/resources/user_team.rb +90 -0
  47. data/lib/latitude/api/resources/virtual_machine.rb +146 -0
  48. data/lib/latitude/api/resources/virtual_network.rb +162 -0
  49. data/lib/latitude/api/resources/vpn_session.rb +80 -0
  50. data/lib/latitude/api/singleton_api_resource.rb +22 -0
  51. data/lib/latitude/api/util.rb +64 -0
  52. data/lib/latitude/api/version.rb +7 -0
  53. data/lib/latitude/api.rb +147 -0
  54. data/lib/latitude/metadata/errors.rb +18 -0
  55. data/lib/latitude/metadata/session.rb +109 -0
  56. data/lib/latitude/metadata.rb +43 -0
  57. data/lib/latitude.rb +4 -0
  58. metadata +132 -0
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Latitude
4
+ module Metadata
5
+ class Session
6
+ BASE_URL = "http://169.254.169.254/metadata/v1"
7
+ TOKEN_REFRESH_RATIO = 0.9
8
+
9
+ JSON_PATHS = %w[tags network storage ssh_keys vendor].freeze
10
+ UNAVAILABLE_EXCEPTIONS = [
11
+ Errno::ECONNREFUSED,
12
+ Errno::EHOSTUNREACH,
13
+ Errno::ENETUNREACH,
14
+ Errno::ETIMEDOUT,
15
+ Net::OpenTimeout,
16
+ Net::ReadTimeout,
17
+ SocketError,
18
+ ].freeze
19
+
20
+ def initialize(ttl: DEFAULT_TTL_SECONDS, open_timeout: 2, read_timeout: 3)
21
+ @ttl = Integer(ttl)
22
+ @open_timeout = open_timeout
23
+ @read_timeout = read_timeout
24
+ @mutex = Mutex.new
25
+ @token = nil
26
+ @token_expires_at = nil
27
+ end
28
+
29
+ def token
30
+ @mutex.synchronize { refresh_token_if_needed }
31
+ end
32
+
33
+ def refresh_token!
34
+ @mutex.synchronize { fetch_new_token }
35
+ end
36
+
37
+ def all
38
+ body = get("metadata.json")
39
+ wrap(JSON.parse(body))
40
+ rescue JSON::ParserError => e
41
+ raise RequestError.new("Invalid JSON from metadata service: #{e.message}")
42
+ end
43
+
44
+ def fetch(path)
45
+ path = path.to_s.sub(%r{\A/}, "")
46
+ body = get(path)
47
+ if JSON_PATHS.include?(path) || path == "metadata.json"
48
+ begin
49
+ wrap(JSON.parse(body))
50
+ rescue JSON::ParserError
51
+ body
52
+ end
53
+ else
54
+ body
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def wrap(value)
61
+ Latitude::API::APIObject.wrap(value)
62
+ end
63
+
64
+ def get(path)
65
+ perform_request(:get, "#{BASE_URL}/#{path}", headers: { "X-Metadata-Token" => token })
66
+ end
67
+
68
+ def perform_request(method, url, headers: {}, body: nil)
69
+ options = {
70
+ headers: headers,
71
+ open_timeout: @open_timeout,
72
+ read_timeout: @read_timeout,
73
+ follow_redirects: false,
74
+ format: :plain,
75
+ }
76
+ options[:body] = body if body
77
+
78
+ response = HTTParty.send(method, url, options)
79
+
80
+ if response.code.between?(200, 299)
81
+ response.body
82
+ else
83
+ raise RequestError.new("metadata service returned #{response.code}", http_status: response.code,
84
+ http_body: response.body)
85
+ end
86
+ rescue *UNAVAILABLE_EXCEPTIONS => e
87
+ raise Unavailable, "metadata service unreachable (#{e.class}: #{e.message}). " \
88
+ "This only works from within a Latitude.sh bare metal server."
89
+ end
90
+
91
+ def refresh_token_if_needed
92
+ fetch_new_token if @token.nil? || @token_expires_at.nil? || Time.now >= @token_expires_at
93
+ @token
94
+ end
95
+
96
+ def fetch_new_token
97
+ body = perform_request(:put, "#{BASE_URL}/api/token",
98
+ headers: { "X-Metadata-Token-TTL-Seconds" => @ttl.to_s })
99
+ raise TokenError, "empty token response" if body.nil? || body.strip.empty?
100
+
101
+ @token = body.strip
102
+ @token_expires_at = Time.now + (@ttl * TOKEN_REFRESH_RATIO)
103
+ @token
104
+ rescue RequestError => e
105
+ raise TokenError, "could not obtain metadata token: #{e.message}"
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "httparty"
4
+
5
+ require "latitude/metadata/errors"
6
+ require "latitude/metadata/session"
7
+
8
+ module Latitude
9
+ module Metadata
10
+ DEFAULT_TTL_SECONDS = 3600
11
+ PATHS = %w[
12
+ instance_id hostname local_ipv4 public_ipv4 public_ipv6 region plan
13
+ operating_system userdata tags network storage ssh_keys vendor
14
+ ].freeze
15
+
16
+ module_function
17
+
18
+ def all(session: default_session)
19
+ session.all
20
+ end
21
+
22
+ PATHS.each do |p|
23
+ define_singleton_method(p) { default_session.fetch(p) }
24
+ end
25
+
26
+ def fetch(path, session: default_session)
27
+ session.fetch(path)
28
+ end
29
+
30
+ def refresh!
31
+ default_session.refresh_token!
32
+ self
33
+ end
34
+
35
+ def reset!
36
+ @default_session = nil
37
+ end
38
+
39
+ def default_session
40
+ @default_session ||= Session.new
41
+ end
42
+ end
43
+ end
data/lib/latitude.rb ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "latitude/api"
4
+ require "latitude/metadata"
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: latitude-api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Josh Brody
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 2026-09-16 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: httparty
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.22'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.22'
26
+ - !ruby/object:Gem::Dependency
27
+ name: logger
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.6'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.6'
40
+ description: A Ruby library for the Latitude.sh REST API. Covers servers, projects,
41
+ virtual machines, Kubernetes clusters, storage, networking, firewalls, elastic IPs,
42
+ SSH keys, teams, and more. Includes a client for the on-instance metadata service.
43
+ email:
44
+ - git@josh.mn
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".yardopts"
50
+ - LICENSE.txt
51
+ - README.md
52
+ - Rakefile
53
+ - lib/latitude.rb
54
+ - lib/latitude/api.rb
55
+ - lib/latitude/api/api_object.rb
56
+ - lib/latitude/api/api_resource.rb
57
+ - lib/latitude/api/attributes.rb
58
+ - lib/latitude/api/client.rb
59
+ - lib/latitude/api/configuration.rb
60
+ - lib/latitude/api/errors.rb
61
+ - lib/latitude/api/json_api.rb
62
+ - lib/latitude/api/list_object.rb
63
+ - lib/latitude/api/objects.rb
64
+ - lib/latitude/api/operations/action.rb
65
+ - lib/latitude/api/operations/create.rb
66
+ - lib/latitude/api/operations/delete.rb
67
+ - lib/latitude/api/operations/list.rb
68
+ - lib/latitude/api/operations/nested.rb
69
+ - lib/latitude/api/operations/retrieve.rb
70
+ - lib/latitude/api/operations/update.rb
71
+ - lib/latitude/api/request_executor.rb
72
+ - lib/latitude/api/request_options.rb
73
+ - lib/latitude/api/request_params.rb
74
+ - lib/latitude/api/resources/api_key.rb
75
+ - lib/latitude/api/resources/billing_usage.rb
76
+ - lib/latitude/api/resources/elastic_ip.rb
77
+ - lib/latitude/api/resources/event.rb
78
+ - lib/latitude/api/resources/firewall.rb
79
+ - lib/latitude/api/resources/ip.rb
80
+ - lib/latitude/api/resources/kubernetes_cluster.rb
81
+ - lib/latitude/api/resources/plan.rb
82
+ - lib/latitude/api/resources/project.rb
83
+ - lib/latitude/api/resources/region.rb
84
+ - lib/latitude/api/resources/role.rb
85
+ - lib/latitude/api/resources/server.rb
86
+ - lib/latitude/api/resources/ssh_key.rb
87
+ - lib/latitude/api/resources/storage_filesystem.rb
88
+ - lib/latitude/api/resources/storage_object.rb
89
+ - lib/latitude/api/resources/storage_volume.rb
90
+ - lib/latitude/api/resources/tag.rb
91
+ - lib/latitude/api/resources/team.rb
92
+ - lib/latitude/api/resources/traffic.rb
93
+ - lib/latitude/api/resources/user_data.rb
94
+ - lib/latitude/api/resources/user_profile.rb
95
+ - lib/latitude/api/resources/user_team.rb
96
+ - lib/latitude/api/resources/virtual_machine.rb
97
+ - lib/latitude/api/resources/virtual_network.rb
98
+ - lib/latitude/api/resources/vpn_session.rb
99
+ - lib/latitude/api/singleton_api_resource.rb
100
+ - lib/latitude/api/util.rb
101
+ - lib/latitude/api/version.rb
102
+ - lib/latitude/metadata.rb
103
+ - lib/latitude/metadata/errors.rb
104
+ - lib/latitude/metadata/session.rb
105
+ homepage: https://github.com/joshmn/latitude-api
106
+ licenses:
107
+ - MIT
108
+ metadata:
109
+ allowed_push_host: https://rubygems.org
110
+ homepage_uri: https://github.com/joshmn/latitude-api
111
+ source_code_uri: https://github.com/joshmn/latitude-api
112
+ changelog_uri: https://github.com/joshmn/latitude-api/blob/main/CHANGELOG.md
113
+ documentation_uri: https://rubydoc.info/gems/latitude-api
114
+ rubygems_mfa_required: 'true'
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: 3.0.0
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubygems_version: 3.6.2
130
+ specification_version: 4
131
+ summary: Ruby client for the Latitude.sh API
132
+ test_files: []