mythic-beasts 0.1.2 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +57 -2
- data/README.md +41 -17
- data/lib/mythic_beasts/auth.rb +3 -0
- data/lib/mythic_beasts/client.rb +23 -7
- data/lib/mythic_beasts/errors.rb +1 -0
- data/lib/mythic_beasts/proxy.rb +151 -0
- data/lib/mythic_beasts/version.rb +1 -1
- data/lib/mythic_beasts/vps.rb +77 -14
- data/lib/mythic_beasts.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b734cfcdd42c515ebf9d1c11d0ccc95067f0da9912fbbe62742de3865265f426
|
|
4
|
+
data.tar.gz: a53d53c0eaf241086e37cf25bad093156e5777edacabf90b291ffadfb43187d9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e464d4d61ac8a68ae5c2615c235e6a0357e1dcf4253a8f6bb961b690b0b97164f8dde32f486f637c29ce77893b6d83f3a0b6e314dd55a8e82a956d4567e5ebf0
|
|
7
|
+
data.tar.gz: 580d8c412f04e39a4a8a3f25604beed9d540655ab83ce7766f60df2dd05752655003105f399b8cd6b1b79c44ba7c9bf6bef1424a76032dd773f386a6f237622b
|
data/CHANGELOG.md
CHANGED
|
@@ -5,9 +5,64 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.2.0] - 2025-11-09
|
|
11
|
+
|
|
12
|
+
### Added in 0.2.0
|
|
13
|
+
|
|
14
|
+
- Interactive CLI tool `mythic-beasts-provision` with numbered menu navigation for VPS provisioning
|
|
15
|
+
- Interactive VPS management tool `mythic-beasts-manage-vps` with DNS and proxy configuration
|
|
16
|
+
- IPv4 to IPv6 Proxy API client (`MythicBeasts.client.proxy`) for managing proxy endpoints
|
|
17
|
+
- List, create, replace, and delete proxy configurations
|
|
18
|
+
- Support for all proxy sites (sov, ams, hex) or "all"
|
|
19
|
+
- Convenience method `create_simple` for quick proxy setup
|
|
20
|
+
- Full CRUD operations on proxy endpoints by domain/hostname/address
|
|
21
|
+
- DNS record verification after proxy configuration
|
|
22
|
+
- DNS management integration in manage-vps tool
|
|
23
|
+
|
|
24
|
+
### Changed in 0.2.0
|
|
25
|
+
|
|
26
|
+
- Replaced tty-prompt with simple numbered menus for better terminal compatibility (especially Ghostty)
|
|
27
|
+
- Smart bandwidth display: shows GB for >= 1024MB, MB otherwise
|
|
28
|
+
|
|
29
|
+
### Fixed in 0.2.0
|
|
30
|
+
|
|
31
|
+
- Zones endpoint now uses correct `/beta/vps/zones` path
|
|
32
|
+
- DNS verification now handles non-array responses correctly
|
|
33
|
+
- DNS records method name corrected in provision-vps tool
|
|
34
|
+
- VPS provisioning polling now waits for actual completion
|
|
35
|
+
- Status polling output now uses newlines properly
|
|
36
|
+
- IPv4 allocation during VPS provisioning
|
|
37
|
+
- Bandwidth display showing MB correctly instead of 0GB
|
|
38
|
+
|
|
39
|
+
## [0.1.3] - 2025-11-05
|
|
40
|
+
|
|
41
|
+
### Fixed in 0.1.3
|
|
42
|
+
|
|
43
|
+
- Bearer token authentication for VPS API endpoints - now sets Authorization header on each request
|
|
44
|
+
- VPS API endpoints now use correct `/beta/vps/*` paths instead of `/vps/*`
|
|
45
|
+
- Location header now captured from 202 Accepted responses for polling async operations
|
|
46
|
+
- Improved error messages to show API response body for better debugging
|
|
47
|
+
|
|
48
|
+
### Added to 0.1.3
|
|
49
|
+
|
|
50
|
+
- `VPS#images` method to list available OS images from `/beta/vps/images`
|
|
51
|
+
- `VPS#products` method to list available VPS products from `/beta/vps/products`
|
|
52
|
+
- `VPS#disk_sizes` method to list available disk sizes from `/beta/vps/disk-sizes`
|
|
53
|
+
- `VPS#zones` method to list available zones from `/beta/vps/zones`
|
|
54
|
+
- Example script `list_vps_options.rb` to display all available VPS configuration options
|
|
55
|
+
|
|
56
|
+
### Changed in 0.1.3
|
|
57
|
+
|
|
58
|
+
- VPS creation now requires `product:` parameter (e.g., `VPSX16`) instead of `type:`
|
|
59
|
+
- VPS creation now requires `ssh_keys:` parameter instead of `ssh_key:`
|
|
60
|
+
- VPS creation now uses `zone:` parameter instead of `location:`
|
|
61
|
+
- 404 errors now show the full URL and HTTP method that failed
|
|
62
|
+
|
|
8
63
|
## [0.1.2] - 2025-11-05
|
|
9
64
|
|
|
10
|
-
### Added
|
|
65
|
+
### Added in 0.1.2
|
|
11
66
|
|
|
12
67
|
- VPS zones listing method (`MythicBeasts.client.vps.zones`) to query available datacenters
|
|
13
68
|
- VPS types listing method (`MythicBeasts.client.vps.types`) to query available VPS plans
|
|
@@ -19,7 +74,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
19
74
|
- `ipv6_only_vps.rb` - IPv6-only VPS with proxy setup guide
|
|
20
75
|
- Test coverage for IPv6-only VPS provisioning
|
|
21
76
|
|
|
22
|
-
### Changed
|
|
77
|
+
### Changed in 0.1.2
|
|
23
78
|
|
|
24
79
|
- Updated README with new VPS methods and examples
|
|
25
80
|
- Improved VPS create documentation with optional parameters
|
data/README.md
CHANGED
|
@@ -86,14 +86,37 @@ MythicBeasts.client.dns.dynamic_update('home.example.com')
|
|
|
86
86
|
|
|
87
87
|
### VPS Management
|
|
88
88
|
|
|
89
|
+
#### Interactive CLI Tool (Recommended)
|
|
90
|
+
|
|
91
|
+
The gem includes an interactive CLI for easy VPS provisioning with numbered menus:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# With 1Password
|
|
95
|
+
op run --env-file=.env.1password -- mythic-beasts-provision
|
|
96
|
+
|
|
97
|
+
# Or with environment variables
|
|
98
|
+
export MYTHIC_BEASTS_API_KEY="your_key"
|
|
99
|
+
export MYTHIC_BEASTS_API_SECRET="your_secret"
|
|
100
|
+
mythic-beasts-provision
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The CLI will guide you through selecting options by number:
|
|
104
|
+
|
|
105
|
+
- Selecting product (VPS size)
|
|
106
|
+
- Choosing datacenter/zone
|
|
107
|
+
- Picking OS image
|
|
108
|
+
- Setting disk size
|
|
109
|
+
- Network configuration (IPv4/IPv6)
|
|
110
|
+
- Server naming
|
|
111
|
+
|
|
112
|
+
#### Programmatic API
|
|
113
|
+
|
|
89
114
|
```ruby
|
|
90
|
-
# List available
|
|
115
|
+
# List available options
|
|
91
116
|
zones = MythicBeasts.client.vps.zones
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
types = MythicBeasts.client.vps.types
|
|
96
|
-
# => ["VPS-1", "VPS-2", "VPS-3", ...]
|
|
117
|
+
products = MythicBeasts.client.vps.products
|
|
118
|
+
images = MythicBeasts.client.vps.images
|
|
119
|
+
disk_sizes = MythicBeasts.client.vps.disk_sizes
|
|
97
120
|
|
|
98
121
|
# List all VPS servers
|
|
99
122
|
servers = MythicBeasts.client.vps.list
|
|
@@ -103,13 +126,14 @@ server = MythicBeasts.client.vps.get('my-server')
|
|
|
103
126
|
|
|
104
127
|
# Create a new VPS
|
|
105
128
|
MythicBeasts.client.vps.create(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
129
|
+
product: 'VPSX16', # Required: product code (e.g., VPSX16 = 2 cores, 4GB RAM)
|
|
130
|
+
name: 'my-new-server', # Optional: friendly name
|
|
131
|
+
hostname: 'my-server', # Optional: server hostname
|
|
132
|
+
ssh_keys: 'ssh-rsa AAAAB3...', # Optional: SSH public key(s)
|
|
133
|
+
zone: 'cam', # Optional: datacenter code (e.g., 'cam' for Cambridge)
|
|
134
|
+
image: 'cloudinit-debian-bookworm.raw.gz', # Optional: OS image
|
|
135
|
+
disk_size: 20480, # Required: disk size in MB
|
|
136
|
+
ipv4: false # Optional: false for IPv6-only (cheaper)
|
|
113
137
|
)
|
|
114
138
|
|
|
115
139
|
# Control servers
|
|
@@ -124,16 +148,16 @@ console = MythicBeasts.client.vps.console('my-server')
|
|
|
124
148
|
MythicBeasts.client.vps.delete('my-server')
|
|
125
149
|
```
|
|
126
150
|
|
|
127
|
-
#### IPv6-Only Servers
|
|
151
|
+
#### IPv6-Only Servers
|
|
128
152
|
|
|
129
153
|
Provision cheaper IPv6-only servers without IPv4 addresses. Perfect for services accessible via Mythic Beasts' IPv4-to-IPv6 proxy:
|
|
130
154
|
|
|
131
155
|
```ruby
|
|
132
|
-
# Create an IPv6-only VPS
|
|
156
|
+
# Create an IPv6-only VPS
|
|
133
157
|
MythicBeasts.client.vps.create(
|
|
134
158
|
name: 'my-ipv6-server',
|
|
135
159
|
type: 'VPS-2',
|
|
136
|
-
ipv4: false,
|
|
160
|
+
ipv4: false,
|
|
137
161
|
ssh_key: 'ssh-rsa AAAAB3...',
|
|
138
162
|
location: 'london'
|
|
139
163
|
)
|
|
@@ -242,7 +266,7 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/tastyb
|
|
|
242
266
|
|
|
243
267
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
244
268
|
|
|
245
|
-
Copyright
|
|
269
|
+
Copyright © 2025, Otaina Limited
|
|
246
270
|
|
|
247
271
|
## Resources
|
|
248
272
|
|
data/lib/mythic_beasts/auth.rb
CHANGED
|
@@ -36,6 +36,9 @@ module MythicBeasts
|
|
|
36
36
|
@token = data["access_token"]
|
|
37
37
|
# Expire token 30 seconds before actual expiry to be safe
|
|
38
38
|
@token_expires_at = Time.now + (data["expires_in"].to_i - 30)
|
|
39
|
+
rescue Faraday::UnauthorizedError => e
|
|
40
|
+
response_body = e.response&.dig(:body)
|
|
41
|
+
raise AuthenticationError, "Failed to authenticate with Mythic Beasts API. Check your API key and secret. Response: #{response_body}"
|
|
39
42
|
rescue Faraday::Error => e
|
|
40
43
|
raise AuthenticationError, "Failed to authenticate: #{e.message}"
|
|
41
44
|
end
|
data/lib/mythic_beasts/client.rb
CHANGED
|
@@ -2,12 +2,13 @@ module MythicBeasts
|
|
|
2
2
|
class Client
|
|
3
3
|
API_BASE_URL = "https://api.mythic-beasts.com"
|
|
4
4
|
|
|
5
|
-
attr_reader :auth, :dns, :vps
|
|
5
|
+
attr_reader :auth, :dns, :vps, :proxy
|
|
6
6
|
|
|
7
7
|
def initialize(api_key:, api_secret:)
|
|
8
8
|
@auth = Auth.new(api_key: api_key, api_secret: api_secret)
|
|
9
9
|
@dns = DNS.new(self)
|
|
10
10
|
@vps = VPS.new(self)
|
|
11
|
+
@proxy = Proxy.new(self)
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def get(path, params: {})
|
|
@@ -22,6 +23,10 @@ module MythicBeasts
|
|
|
22
23
|
request(:put, path, body: body, params: params)
|
|
23
24
|
end
|
|
24
25
|
|
|
26
|
+
def patch(path, body: {}, params: {})
|
|
27
|
+
request(:patch, path, body: body, params: params)
|
|
28
|
+
end
|
|
29
|
+
|
|
25
30
|
def delete(path, params: {})
|
|
26
31
|
request(:delete, path, params: params)
|
|
27
32
|
end
|
|
@@ -31,22 +36,34 @@ module MythicBeasts
|
|
|
31
36
|
def request(method, path, body: {}, params: {})
|
|
32
37
|
response = connection.send(method) do |req|
|
|
33
38
|
req.url path
|
|
39
|
+
req.headers["Authorization"] = "Bearer #{auth.token}"
|
|
34
40
|
req.params = params if params.any?
|
|
35
41
|
req.body = body.to_json if body.any?
|
|
36
42
|
end
|
|
37
43
|
|
|
38
|
-
JSON.parse(response.body) if response.body && !response.body.empty?
|
|
44
|
+
result = JSON.parse(response.body) if response.body && !response.body.empty?
|
|
45
|
+
|
|
46
|
+
# For 202 Accepted responses, include Location header for polling
|
|
47
|
+
if response.status == 202 && response.headers["location"]
|
|
48
|
+
result ||= {}
|
|
49
|
+
result["location"] = response.headers["location"]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
result
|
|
39
53
|
rescue Faraday::UnauthorizedError, Faraday::ClientError => e
|
|
54
|
+
response_body = e.response&.dig(:body)
|
|
40
55
|
if e.response&.dig(:status) == 401
|
|
41
|
-
raise AuthenticationError, "Invalid credentials"
|
|
56
|
+
raise AuthenticationError, "Invalid credentials - #{response_body}"
|
|
42
57
|
elsif e.response&.dig(:status) == 404
|
|
43
|
-
raise NotFoundError,
|
|
58
|
+
raise NotFoundError, "the server responded with status 404 for #{method.to_s.upcase} #{API_BASE_URL}#{path}"
|
|
44
59
|
elsif e.response&.dig(:status) == 400
|
|
45
|
-
raise ValidationError, e.message
|
|
60
|
+
raise ValidationError, "#{e.message} - #{response_body}"
|
|
61
|
+
elsif e.response&.dig(:status) == 409
|
|
62
|
+
raise ConflictError, "#{e.message} - #{response_body}"
|
|
46
63
|
elsif e.response&.dig(:status) == 429
|
|
47
64
|
raise RateLimitError, e.message
|
|
48
65
|
else
|
|
49
|
-
raise Error, e.message
|
|
66
|
+
raise Error, "#{e.message} - #{response_body}"
|
|
50
67
|
end
|
|
51
68
|
rescue Faraday::ServerError => e
|
|
52
69
|
raise ServerError, e.message
|
|
@@ -54,7 +71,6 @@ module MythicBeasts
|
|
|
54
71
|
|
|
55
72
|
def connection
|
|
56
73
|
@connection ||= Faraday.new(url: API_BASE_URL) do |conn|
|
|
57
|
-
conn.request :authorization, :bearer, -> { auth.token }
|
|
58
74
|
conn.request :json
|
|
59
75
|
conn.request :retry, {
|
|
60
76
|
max: 3,
|
data/lib/mythic_beasts/errors.rb
CHANGED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MythicBeasts
|
|
4
|
+
# IPv4 to IPv6 Proxy API
|
|
5
|
+
#
|
|
6
|
+
# Manages IPv4-to-IPv6 proxy endpoints for making IPv6-only servers
|
|
7
|
+
# accessible via IPv4. Useful for cost-effective IPv6-only VPS deployments.
|
|
8
|
+
#
|
|
9
|
+
# @see https://www.mythic-beasts.com/support/api/proxy
|
|
10
|
+
class Proxy
|
|
11
|
+
# @param client [MythicBeasts::Client] the API client
|
|
12
|
+
def initialize(client)
|
|
13
|
+
@client = client
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# List all proxy endpoints accessible to the authenticated user
|
|
17
|
+
#
|
|
18
|
+
# @return [Array<Hash>] array of endpoint configurations
|
|
19
|
+
# @example
|
|
20
|
+
# endpoints = client.proxy.list
|
|
21
|
+
# # => [{"domain" => "example.com", "hostname" => "www", "address" => "2a00:...", "site" => "all"}]
|
|
22
|
+
def list
|
|
23
|
+
response = @client.get("/proxy/endpoints")
|
|
24
|
+
response["endpoints"] || response[:endpoints] || []
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# List proxy endpoints for a specific domain
|
|
28
|
+
#
|
|
29
|
+
# @param domain [String] the domain name
|
|
30
|
+
# @return [Array<Hash>] array of endpoint configurations for the domain
|
|
31
|
+
# @example
|
|
32
|
+
# endpoints = client.proxy.list_for_domain("example.com")
|
|
33
|
+
def list_for_domain(domain)
|
|
34
|
+
response = @client.get("/proxy/endpoints/#{domain}")
|
|
35
|
+
response["endpoints"] || response[:endpoints] || []
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# List proxy endpoints for a specific hostname
|
|
39
|
+
#
|
|
40
|
+
# @param domain [String] the domain name
|
|
41
|
+
# @param hostname [String] the hostname (use "@" for the domain itself)
|
|
42
|
+
# @return [Array<Hash>] array of endpoint configurations
|
|
43
|
+
# @example
|
|
44
|
+
# endpoints = client.proxy.list_for_hostname("example.com", "www")
|
|
45
|
+
def list_for_hostname(domain, hostname)
|
|
46
|
+
response = @client.get("/proxy/endpoints/#{domain}/#{hostname}")
|
|
47
|
+
response["endpoints"] || response[:endpoints] || []
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Create or replace proxy endpoints for a hostname
|
|
51
|
+
#
|
|
52
|
+
# This replaces ALL existing endpoints for the hostname.
|
|
53
|
+
#
|
|
54
|
+
# @param domain [String] the domain name
|
|
55
|
+
# @param hostname [String] the hostname (use "@" for the domain itself)
|
|
56
|
+
# @param endpoints [Array<Hash>] array of endpoint configurations
|
|
57
|
+
# @option endpoints [String] :address IPv6 address
|
|
58
|
+
# @option endpoints [String] :site proxy server location or "all"
|
|
59
|
+
# @option endpoints [Boolean] :proxy_protocol enable PROXY protocol (optional)
|
|
60
|
+
# @return [Hash] API response
|
|
61
|
+
# @example
|
|
62
|
+
# client.proxy.replace(
|
|
63
|
+
# "example.com",
|
|
64
|
+
# "www",
|
|
65
|
+
# [{address: "2a00:1098:4c4::1", site: "all"}]
|
|
66
|
+
# )
|
|
67
|
+
def replace(domain, hostname, endpoints)
|
|
68
|
+
@client.put("/proxy/endpoints/#{domain}/#{hostname}", body: {endpoints: endpoints})
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Add proxy endpoints for a hostname without replacing existing ones
|
|
72
|
+
#
|
|
73
|
+
# @param domain [String] the domain name
|
|
74
|
+
# @param hostname [String] the hostname (use "@" for the domain itself)
|
|
75
|
+
# @param endpoints [Array<Hash>] array of endpoint configurations
|
|
76
|
+
# @option endpoints [String] :address IPv6 address
|
|
77
|
+
# @option endpoints [String] :site proxy server location or "all"
|
|
78
|
+
# @option endpoints [Boolean] :proxy_protocol enable PROXY protocol (optional)
|
|
79
|
+
# @return [Hash] API response
|
|
80
|
+
# @example
|
|
81
|
+
# client.proxy.add(
|
|
82
|
+
# "example.com",
|
|
83
|
+
# "www",
|
|
84
|
+
# [{address: "2a00:1098:4c4::1", site: "all"}]
|
|
85
|
+
# )
|
|
86
|
+
def add(domain, hostname, endpoints)
|
|
87
|
+
@client.post("/proxy/endpoints/#{domain}/#{hostname}", body: {endpoints: endpoints})
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Delete all proxy endpoints for a hostname
|
|
91
|
+
#
|
|
92
|
+
# @param domain [String] the domain name
|
|
93
|
+
# @param hostname [String] the hostname
|
|
94
|
+
# @return [Hash] API response
|
|
95
|
+
# @example
|
|
96
|
+
# client.proxy.delete("example.com", "www")
|
|
97
|
+
def delete(domain, hostname)
|
|
98
|
+
@client.delete("/proxy/endpoints/#{domain}/#{hostname}")
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Delete a specific proxy endpoint
|
|
102
|
+
#
|
|
103
|
+
# @param domain [String] the domain name
|
|
104
|
+
# @param hostname [String] the hostname
|
|
105
|
+
# @param address [String] the IPv6 address
|
|
106
|
+
# @param site [String] the proxy site (optional, defaults to "all")
|
|
107
|
+
# @return [Hash] API response
|
|
108
|
+
# @example
|
|
109
|
+
# client.proxy.delete_endpoint("example.com", "www", "2a00:1098:4c4::1")
|
|
110
|
+
def delete_endpoint(domain, hostname, address, site = nil)
|
|
111
|
+
path = "/proxy/endpoints/#{domain}/#{hostname}/#{address}"
|
|
112
|
+
path += "/#{site}" if site
|
|
113
|
+
@client.delete(path)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# List available proxy server locations
|
|
117
|
+
#
|
|
118
|
+
# @return [Array<String>] array of site codes (e.g., ["sov", "ams", "hex"])
|
|
119
|
+
# @example
|
|
120
|
+
# sites = client.proxy.sites
|
|
121
|
+
# # => ["sov", "ams", "hex"]
|
|
122
|
+
def sites
|
|
123
|
+
response = @client.get("/proxy/sites")
|
|
124
|
+
response["sites"] || response[:sites] || []
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Convenience method: Create a simple proxy endpoint for a server
|
|
128
|
+
#
|
|
129
|
+
# @param domain [String] the domain name
|
|
130
|
+
# @param hostname [String] the hostname (use "@" for root domain)
|
|
131
|
+
# @param ipv6_address [String] the IPv6 address of your server
|
|
132
|
+
# @param proxy_protocol [Boolean] enable PROXY protocol (default: false)
|
|
133
|
+
# @return [Hash] API response
|
|
134
|
+
# @example
|
|
135
|
+
# # Make staging.example.com point to IPv6-only server
|
|
136
|
+
# client.proxy.create_simple(
|
|
137
|
+
# "example.com",
|
|
138
|
+
# "staging",
|
|
139
|
+
# "2a00:1098:4c4::1"
|
|
140
|
+
# )
|
|
141
|
+
def create_simple(domain, hostname, ipv6_address, proxy_protocol: false)
|
|
142
|
+
endpoint = {
|
|
143
|
+
address: ipv6_address,
|
|
144
|
+
site: "all"
|
|
145
|
+
}
|
|
146
|
+
endpoint[:proxy_protocol] = true if proxy_protocol
|
|
147
|
+
|
|
148
|
+
add(domain, hostname, [endpoint])
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
data/lib/mythic_beasts/vps.rb
CHANGED
|
@@ -11,26 +11,55 @@ module MythicBeasts
|
|
|
11
11
|
client.get("/api/vps")
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
# List all VPS servers (newer endpoint)
|
|
15
|
+
def servers
|
|
16
|
+
client.get("/vps/servers")
|
|
17
|
+
end
|
|
18
|
+
|
|
14
19
|
# Get details of a specific VPS
|
|
15
20
|
def get(server_name)
|
|
16
21
|
client.get("/api/vps/#{server_name}")
|
|
17
22
|
end
|
|
18
23
|
|
|
24
|
+
# Get details of a specific VPS by identifier (newer endpoint)
|
|
25
|
+
def server(identifier)
|
|
26
|
+
client.get("/vps/servers/#{identifier}")
|
|
27
|
+
end
|
|
28
|
+
|
|
19
29
|
# Create a new VPS
|
|
20
30
|
# Options:
|
|
21
|
-
# -
|
|
22
|
-
# -
|
|
23
|
-
# -
|
|
24
|
-
# -
|
|
25
|
-
|
|
31
|
+
# - product: Server product (e.g., 'VPS-1', 'VPS-2') - REQUIRED
|
|
32
|
+
# - name: Friendly name for the server
|
|
33
|
+
# - hostname: Hostname for the server
|
|
34
|
+
# - ssh_keys: SSH public key(s) for access
|
|
35
|
+
# - zone: Datacentre code (e.g., 'london', 'cambridge')
|
|
36
|
+
# - ipv4: Boolean - allocate IPv4 address (default true)
|
|
37
|
+
# - image: Operating system image name
|
|
38
|
+
# - disk_size: Disk size in MB
|
|
39
|
+
# And other optional parameters...
|
|
40
|
+
def create(product:, name: nil, ssh_keys: nil, **options)
|
|
41
|
+
body = {
|
|
42
|
+
product: product,
|
|
43
|
+
**options
|
|
44
|
+
}
|
|
45
|
+
body[:name] = name if name
|
|
46
|
+
body[:ssh_keys] = ssh_keys if ssh_keys
|
|
47
|
+
|
|
48
|
+
client.post("/beta/vps/servers", body: body)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Create a new VPS with a custom identifier
|
|
52
|
+
# Returns 409 Conflict if identifier already exists
|
|
53
|
+
# Options are same as create method
|
|
54
|
+
def create_with_identifier(identifier, product:, name: nil, ssh_keys: nil, **options)
|
|
26
55
|
body = {
|
|
27
|
-
|
|
28
|
-
type: type,
|
|
56
|
+
product: product,
|
|
29
57
|
**options
|
|
30
58
|
}
|
|
31
|
-
body[:
|
|
59
|
+
body[:name] = name if name
|
|
60
|
+
body[:ssh_keys] = ssh_keys if ssh_keys
|
|
32
61
|
|
|
33
|
-
client.post("/
|
|
62
|
+
client.post("/beta/vps/servers/#{identifier}", body: body)
|
|
34
63
|
end
|
|
35
64
|
|
|
36
65
|
# Start a VPS
|
|
@@ -48,24 +77,58 @@ module MythicBeasts
|
|
|
48
77
|
client.post("/api/vps/#{server_name}/restart")
|
|
49
78
|
end
|
|
50
79
|
|
|
80
|
+
# Reboot a VPS by identifier (newer endpoint)
|
|
81
|
+
def reboot(identifier)
|
|
82
|
+
client.post("/vps/servers/#{identifier}/reboot")
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Update a VPS (e.g., mount ISO image)
|
|
86
|
+
# Options:
|
|
87
|
+
# - iso_image: ISO image name to mount
|
|
88
|
+
def update(identifier, **options)
|
|
89
|
+
client.patch("/vps/servers/#{identifier}", body: options)
|
|
90
|
+
end
|
|
91
|
+
|
|
51
92
|
# Delete a VPS
|
|
52
93
|
def delete(server_name)
|
|
53
94
|
client.delete("/api/vps/#{server_name}")
|
|
54
95
|
end
|
|
55
96
|
|
|
97
|
+
# Unprovision (permanently delete) a VPS by identifier (newer endpoint)
|
|
98
|
+
def unprovision(identifier)
|
|
99
|
+
client.delete("/beta/vps/servers/#{identifier}")
|
|
100
|
+
end
|
|
101
|
+
|
|
56
102
|
# Get VPS console access
|
|
57
103
|
def console(server_name)
|
|
58
104
|
client.get("/api/vps/#{server_name}/console")
|
|
59
105
|
end
|
|
60
106
|
|
|
61
|
-
# List available
|
|
107
|
+
# List available ISO images for a specific server
|
|
108
|
+
# These can be mounted to the server for manual OS installation
|
|
109
|
+
def iso_images(server_identifier)
|
|
110
|
+
client.get("/beta/vps/servers/#{server_identifier}/iso-images")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# List available zones/datacenters for VPS provisioning
|
|
62
114
|
def zones
|
|
63
|
-
client.get("/
|
|
115
|
+
client.get("/beta/vps/zones")
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# List available OS images for VPS provisioning
|
|
119
|
+
def images
|
|
120
|
+
client.get("/beta/vps/images")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# List available disk sizes
|
|
124
|
+
# Returns hash with 'ssd' and 'hdd' keys containing arrays of sizes in MB
|
|
125
|
+
def disk_sizes
|
|
126
|
+
client.get("/beta/vps/disk-sizes")
|
|
64
127
|
end
|
|
65
128
|
|
|
66
|
-
# List available
|
|
67
|
-
def
|
|
68
|
-
client.get("/
|
|
129
|
+
# List available products
|
|
130
|
+
def products
|
|
131
|
+
client.get("/beta/vps/products")
|
|
69
132
|
end
|
|
70
133
|
end
|
|
71
134
|
end
|
data/lib/mythic_beasts.rb
CHANGED
|
@@ -7,6 +7,7 @@ require_relative "mythic_beasts/client"
|
|
|
7
7
|
require_relative "mythic_beasts/auth"
|
|
8
8
|
require_relative "mythic_beasts/dns"
|
|
9
9
|
require_relative "mythic_beasts/vps"
|
|
10
|
+
require_relative "mythic_beasts/proxy"
|
|
10
11
|
require_relative "mythic_beasts/errors"
|
|
11
12
|
|
|
12
13
|
module MythicBeasts
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mythic-beasts
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- James Inman
|
|
@@ -165,6 +165,7 @@ files:
|
|
|
165
165
|
- lib/mythic_beasts/client.rb
|
|
166
166
|
- lib/mythic_beasts/dns.rb
|
|
167
167
|
- lib/mythic_beasts/errors.rb
|
|
168
|
+
- lib/mythic_beasts/proxy.rb
|
|
168
169
|
- lib/mythic_beasts/version.rb
|
|
169
170
|
- lib/mythic_beasts/vps.rb
|
|
170
171
|
homepage: https://github.com/tastybamboo/mythic-beasts
|