I wrote a Ruby library for operating Contabo instances from code.
This library has 3 following features:
instance creation
instance cancelation
instance reinstalling
I need your help with the documentation/
Here is the souce code of the library:
require 'net/http'
require 'json'
require 'uri'
require 'securerandom'
class ContaboClient
def initialize(client_id:, client_secret:, api_user:, api_password:)
@client_id = client_id
@client_secret = client_secret
@api_user = api_user
@api_password = api_password
@auth_url = 'https://auth.contabo.com/auth/realms/contabo/protocol/openid-connect/token'
@api_url = 'https://api.contabo.com/v1/compute/instances'
end
def get_access_token
uri = URI(@auth_url)
response = Net::HTTP.post_form(uri, {
'client_id' => @client_id,
'client_secret' => @client_secret,
'username' => @api_user,
'password' => @api_password,
'grant_type' => 'password'
})
JSON.parse(response.body)['access_token']
end
def create_secret(password, type = 'password')
uri = URI('https://api.contabo.com/v1/secrets')
request = Net::HTTP::Post.new(uri)
request['Authorization'] = "Bearer #{access_token}"
request['Content-Type'] = 'application/json'
request['x-request-id'] = SecureRandom.uuid
body = {
name: "Ruby's Contabo Client #{SecureRandom.uuid}",
value: password,
type: type
}
request.body = body.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
data = JSON.parse(response.body)['data'].first
raise "Failed to create secret. Error: #{response.body}" if data.nil?
data['secretId']
end
def retrieve_images(page: 1, size: 10)
uri = URI('https://api.contabo.com/v1/compute/images')
params = { page: page, size: size }
uri.query = URI.encode_www_form(params)
request = Net::HTTP::Get.new(uri)
request['Authorization'] = "Bearer #{access_token}"
request['x-request-id'] = SecureRandom.uuid
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
JSON.parse(response.body)
end
def get_instances(page: 1, size: 10, order_by: nil, search: nil)
uri = URI(@api_url)
params = { page: page, size: size }
params[:orderBy] = order_by if order_by
params[:search] = search if search
uri.query = URI.encode_www_form(params)
request = Net::HTTP::Get.new(uri)
request['Authorization'] = "Bearer #{access_token}"
request['x-request-id'] = SecureRandom.uuid
request['x-request-id'] = SecureRandom.uuid
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
JSON.parse(response.body)
end
def create_instance(image_id:, product_id:, region: 'EU', ssh_rsa:, root_password:, display_name:, user_data: '')
uri = URI(@api_url)
request = Net::HTTP::Post.new(uri)
request['Authorization'] = "Bearer #{access_token}"
request['Content-Type'] = 'application/json'
request['x-request-id'] = SecureRandom.uuid
root_password_secret_id = create_secret(root_password)
root_ssh_secret_id = create_secret(ssh_rsa, 'ssh')
body = {
imageId: image_id,
productId: product_id,
region: region,
sshKeys: [root_ssh_secret_id],
rootPassword: root_password_secret_id,
defaultUser: "root",
displayName: display_name,
userData: user_data
}.compact
request.body = body.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
JSON.parse(response.body)
end
def reinstall_instance(instance_id:, image_id:, root_password:, cloud_init: nil, user_data: '')
uri = URI("https://api.contabo.com/v1/compute/instances/#{instance_id}")
request = Net::HTTP::Put.new(uri)
request['Authorization'] = "Bearer #{access_token}"
request['Content-Type'] = 'application/json'
request['x-request-id'] = SecureRandom.uuid
root_password_secret_id = create_secret(root_password)
body = {
imageId: image_id,
rootPassword: root_password_secret_id,
defaultUser: "root",
userData: user_data
}.compact
request.body = body.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
JSON.parse(response.body)
end
def access_token
@access_token ||= get_access_token
end
def cancel_instance(instance_id:)
uri = URI("#{@api_url}/#{instance_id}/cancel")
request = Net::HTTP::Post.new(uri)
request['Authorization'] = "Bearer #{access_token}"
request['x-request-id'] = SecureRandom.uuid
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
JSON.parse(response.body)
rescue StandardError => e
puts "Error canceling instance: #{e.message}"
nil
end
end
Here is the source code of the creation example:
require_relative '../lib/contabo-client'
require_relative './config.rb'
require 'blackstack-core'
require 'colorize'
require 'json'
require 'pry'
# Initialize Contabo client
client = ContaboClient.new(
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
api_user: API_USER,
api_password: API_PASSWORD
)
# Retrieve images with error handling
begin
# Fetch initial set of images
ret = client.retrieve_images(size: 100)
raise "Unexpected response format or empty response" unless ret && ret['_pagination'] && ret['data']
# Find the image ID for Ubuntu 20.04
image = ret['data'].find { |h| h['name'] == 'ubuntu-20.04' }
raise 'Image not found' if image.nil?
image_id = image['imageId']
# Set the root password directly here
root_password = 'HGT121124588ABC'
# use the following command to generate ssh key
# ssh-keygen -t ed25519 -b 4096 -C "your_email_here" -f "key_name_here"
ssh_rsa = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMPfaX2P18lDbtoZsGC6fcqw7zoAbbNyGlrUI004QCe7 schaudhry722@gmail.com"
user_data_script = <<~USER_DATA
#cloud-config
disable_cloud_init: true
runcmd:
- touch /etc/cloud/cloud-init.disabled
- systemctl stop cloud-init
- systemctl disable cloud-init
USER_DATA
# Create the instance with the retrieved image ID
instance = client.create_instance(
image_id: image_id,
product_id: 'V45',
region: 'EU',
ssh_rsa: ssh_rsa,
root_password: root_password,
display_name: 'MyUbuntu20Instance-root-access-6',
user_data: user_data_script
)
# Output the created instance details
# Commented out since we're using binding.pry for debugging
puts JSON.pretty_generate(instance)
rescue StandardError => e
STDERR.puts "An error occurred: #{e.to_console}".red
end
Here is the source code of the cancellation example:
require_relative '../lib/contabo-client'
require_relative './config.rb'
require 'blackstack-core'
require 'colorize'
require 'json'
# Constants
Z = 100
IP = '62.84.178.201'
# Initialize Contabo client
client = ContaboClient.new(
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
api_user: API_USER,
api_password: API_PASSWORD
)
begin
# Retrieve instances
instances = client.get_instances(size: Z)
# Debug prints to inspect response
#puts "Response from get_instances:"
if instances.nil?
puts "Received nil response from get_instances."
exit
else
puts JSON.pretty_generate(instances)
end
# Check for errors in the response
if instances['error']
puts "API returned an error: #{instances['error']}"
exit
end
# Check if 'data' key is present and is an array
if instances['data'].nil? || !instances['data'].is_a?(Array)
puts "No instances returned or unexpected data format. Response: #{instances.inspect}"
exit
end
unless instances['data'].any?
puts "No instances found"
exit
end
# Find the instance ID by IP
instance = instances['data'].find do |h|
ip_config_v4 = h.dig('ipConfig', 'v4')
ip_config_v4.is_a?(Hash) && ip_config_v4['ip'] == IP
end
if instance.nil?
puts "Instance with IP #{IP} not found in the retrieved instances."
exit
end
# Use the correct instance ID for cancellation
instance_id = instance['instanceId']
# Debug: Print the instance details
puts "Found instance with IP #{IP}"
#puts JSON.pretty_generate(instance)
# Request cancellation
response = client.cancel_instance(instance_id: instance_id)
# Print the response
puts "Cancellation response:"
if response.nil?
puts "Received nil response from cancel_instance."
else
puts JSON.pretty_generate(response)
end
rescue StandardError => e
STDERR.puts "An error occurred: #{e.to_console}".red
end
Here is the source code of the reinstallation example:
require_relative '../lib/contabo-client'
require_relative './config.rb'
require 'blackstack-core'
require 'colorize'
require 'json'
# Constants
Z = 100
IP = '62.84.178.201'
# Initialize Contabo client
client = ContaboClient.new(
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
api_user: API_USER,
api_password: API_PASSWORD
)
begin
# Retrieve instances
instances = client.get_instances(size: Z)
# Debug prints to inspect response
#puts "Response from get_instances:"
if instances.nil?
puts "Received nil response from get_instances."
exit
else
puts JSON.pretty_generate(instances)
end
# Check for errors in the response
if instances['error']
puts "API returned an error: #{instances['error']}"
exit
end
# Check if 'data' key is present and is an array
if instances['data'].nil? || !instances['data'].is_a?(Array)
puts "No instances returned or unexpected data format. Response: #{instances.inspect}"
exit
end
unless instances['data'].any?
puts "No instances found"
exit
end
# Find the instance ID by IP
instance = instances['data'].find do |h|
ip_config_v4 = h.dig('ipConfig', 'v4')
ip_config_v4.is_a?(Hash) && ip_config_v4['ip'] == IP
end
if instance.nil?
puts "Instance with IP #{IP} not found in the retrieved instances."
exit
end
# Use the correct instance ID for cancellation
instance_id = instance['instanceId']
# Debug: Print the instance details
puts "Found instance with IP #{IP}"
#puts JSON.pretty_generate(instance)
# Request cancellation
response = client.cancel_instance(instance_id: instance_id)
# Print the response
puts "Cancellation response:"
if response.nil?
puts "Received nil response from cancel_instance."
else
puts JSON.pretty_generate(response)
end
rescue StandardError => e
STDERR.puts "An error occurred: #{e.to_console}".red
end
GPT Prompt
I wrote a Ruby library for operating Contabo instances from code.
This library has 3 following features:
I need your help with the documentation/
Here is the souce code of the library:
Here is the source code of the creation example:
Here is the source code of the cancellation example:
Here is the source code of the reinstallation example:
Please write the README.md file.