Closed leandrosardi closed 1 week ago
Prompt:
From this requirement, I need you create a Ruby method add_node(h)
that validates the hash descriptor h
. Add all the errors into an array err
. After validation, if the array err
has one or more elements, raise an exception with all the errors found in the hash descritor h
. If there is not any error, create an instance of BlackStack::Infrastructure::Node
passing h
as a parameter of the constructure, and then add such an instance to the statuc arraw @nodes.
Please don't give me a file to download, but write the Ruby code here instead.
Here is the requirement for more details:
This is the MySaaS part.
You can add a node to your infrastructure as follows:
BlackStack::Deployment.add_node({
# Unique name to identify a host (a.k.a.: node).
# It is equal to the hostname of the node.
#
# Mandatory.
#
# Allowed values: string with a valid hostname.
#
:name => 'master',
# If true, this node is belonging your development environment.
# If true, ignore this node when deploying.
#
# Optional. Default: false.
#
# Allowed values: boolean.
#
:dev => false,
# Public Internet IP address of the node.
# If `nil`, that means that no instance of a cloud server has been created yet for this node.
#
# Optional. Default: `nil`.
#
# Allowed values: string with a valid IP address.
#
:net_remote_ip => nil,
# Who is providing this node.
# Allowed values: [:contabo].
#
# Optional. Default: :contabo.
#
# Allowed values: symbol with one of the following values [:contabo].
#
:provider => :contabo,
# What service is this.
# If :provider is :contabo, allowed values are ['CLOUD VPS 1', 'CLOUD VPS 3', 'CLOUD VPS 6']
#
# Mandatory.
#
# Allowed values: string with one of the following values ['CLOUD VPS 1', 'CLOUD VPS 3', 'CLOUD VPS 6'].
#
:service => 'CLOUD VPS 1',
# Reference to another node where is hosted the database to work with.
#
# Mandatory.
#
# Allowed values: string with a valid PostgreSQL database name,
#
:db_host => 'dev2',
# SSH credentials.
# Root password is required to install the environment at the first time.
#
# Mandatory. The 4 keys below are mandatory.
#
# Allowed values:
# - ssh_username: string with a valid Linus user name,
# - ssh_port: integer with a valid port number
# - ssh_password: string with a valid Linux password.
# - ssh_root_password: string with a valid Linux password.
#
:ssh_username => 'blackstack',
:ssh_port => 22,
:ssh_password => '<write SSH password here>',
:ssh_root_password => '<write SSH password here>',
# Parameters to connect to the github repositories.
#
# Instead of GitHub password, you have to provide an access token.
# How to get a GitHub access token: https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app
#
# Mandatory. The 4 keys below are mandatory.
#
# Allowed values:
# - git_repository: string that a can concatenate to 'https://github.com/' and get a valid URL of a GitHub repository.
# - git_branch: integer with a valid GitHub branch name.
# - git_username: string with a valid GitHub username.
# - git_password: string with a valid GitHub password.
#
:git_repository => 'leandrosardi/my.saas',
:git_branch => 'main',
:git_username => 'leandrosardi',
:git_password => '<your github access token>',
# Folder into where you want to clone the repository defined in `git_repository`.
#
# Mandatory.
#
# Allowed values: string with a valid Linux full path to a folder. Relative paths are not allowed.
#
:code_folder => '/home/blackstack/code1/master',
# List of processes to start
#
# Optional. Default: [].
#
# Allowed values: (TODO: pendng)
#
:procs => {
# list of commands to run when starting a node.
:start => [
{
# the command you are executing must be located into `code_folder`.
:command => 'app.rb port=3000',
# where to redirect any output in the starting of this command.
# note that the command may log into another file once it started.
:stdout => '/home/blackstack/code1/master/app.log',
:stderr => '/home/blackstack/code1/master',
# value to assign to the environment variable `$RUBYLIB`
:rubylib => '/home/blackstack/code1/master',
}, {
...
}
],
# list of commands to kill when stopping a node.
:stop => [
'app.rb port=3000',
'adspower',
...
],
},
# List of logfiles allowed to watch or monitor.
#
# Optional. Default: [].
#
# Allowed values: (TODO: pendng)
#
:logs => [
'/home/blackstack/code1/master/app.log',
...
],
# List of websites published on this node.
# This is used for monitoring.
#
# Optional. Default: [].
#
# Allowed values: (TODO: pendng)
#
:webs => [
{
# descriptive name of this website.
:name => 'ruby-sinatra',
# port this website is listening.
:port => 3000,
# protocol used. Allowed values are [:http, :https].
:protocol => :http,
}, {
# descriptive name of this website.
:name => 'nginx',
# port this website is listening.
:port => 443,
# protocol used. Allowed values are [:http, :https].
:protocol => :https,
}
],
})
When you call BlackStack::Deployment.add_node
to add a node to your infrastructure, a new instance of the class BlackStack::Infrastructure::Node
will be created and added to the arraw @nodes
of the module BlackStack::Deployment
.
For more information about the BlackStack::Infrastructure::Node
class, refer to our BlackStack Nodes library.
Note that if the hash descriptor passed to the add_node
method has not the right format, of if there are missed parameters, or if there are unknown parameters; then such a method will raise an exception Node hash descriptor mailformed.
GPT - Try 1
First Response from GPT:
module BlackStack
module Deployment
@nodes = []
def self.add_node(h)
err = []
# Validate :name
if !h.key?(:name) || !h[:name].is_a?(String) || h[:name].empty?
err << "Invalid or missing :name. It must be a non-empty string."
end
# Validate :dev
if h.key?(:dev) && ![true, false].include?(h[:dev])
err << "Invalid :dev. It must be a boolean."
end
# Validate :net_remote_ip (optional)
if h.key?(:net_remote_ip) && !(h[:net_remote_ip].nil? || h[:net_remote_ip].is_a?(String))
err << "Invalid :net_remote_ip. It must be a string or nil."
end
# Validate :provider
if h.key?(:provider) && ![:contabo].include?(h[:provider])
err << "Invalid :provider. Allowed value is :contabo."
end
# Validate :service
if !h.key?(:service) || !['CLOUD VPS 1', 'CLOUD VPS 3', 'CLOUD VPS 6'].include?(h[:service])
err << "Invalid or missing :service. Allowed values are 'CLOUD VPS 1', 'CLOUD VPS 3', 'CLOUD VPS 6'."
end
# Validate :db_host
if !h.key?(:db_host) || !h[:db_host].is_a?(String) || h[:db_host].empty?
err << "Invalid or missing :db_host. It must be a non-empty string."
end
# Validate SSH credentials
[:ssh_username, :ssh_port, :ssh_password, :ssh_root_password].each do |key|
if !h.key?(key) || (key == :ssh_port && !h[key].is_a?(Integer)) || (key != :ssh_port && !h[key].is_a?(String))
err << "Invalid or missing #{key}. It must be a #{key == :ssh_port ? 'integer' : 'non-empty string'}."
end
end
# Validate GitHub credentials
[:git_repository, :git_branch, :git_username, :git_password].each do |key|
if !h.key?(key) || !h[key].is_a?(String) || h[key].empty?
err << "Invalid or missing #{key}. It must be a non-empty string."
end
end
# Validate :code_folder
if !h.key?(:code_folder) || !h[:code_folder].is_a?(String) || h[:code_folder].empty?
err << "Invalid or missing :code_folder. It must be a non-empty string representing a full Linux path."
end
# If there are any errors, raise an exception
raise "Node hash descriptor malformed. Errors: #{err.join(', ')}" unless err.empty?
# Create the instance of BlackStack::Infrastructure::Node
node = BlackStack::Infrastructure::Node.new(h)
# Add the node to @nodes
@nodes << node
end
end
end
GPT - Try 1
In the comment above, note that GPT missed to validate the entries :procs
, :logs
and :webs
.
Note that the comments for these 3 entries are not complete yet (TODO
), so I think it is the reason why GPT missed them.
Lesson Learned: You must to give GPT a PRECISE REQUIREMENT.
So, your next step @hagom is to complete the documentation, and then ask GPT to write the validations for the 3 entries pending.
Since these 3 entries are hash descritors themselves, you have to write specificatins for the entries inside them too. What is optional and what is mandatory? What is the default value? What are the allowed values?
...
# List of processes to start
#
# Optional. Default: [].
#
# Allowed values: (TODO: pendng)
#
:procs => {
# list of commands to run when starting a node.
:start => [
{
# the command you are executing must be located into `code_folder`.
:command => 'app.rb port=3000',
# where to redirect any output in the starting of this command.
# note that the command may log into another file once it started.
:stdout => '/home/blackstack/code1/master/app.log',
:stderr => '/home/blackstack/code1/master',
# value to assign to the environment variable `$RUBYLIB`
:rubylib => '/home/blackstack/code1/master',
}, {
...
}
],
# list of commands to kill when stopping a node.
:stop => [
'app.rb port=3000',
'adspower',
...
],
},
# List of logfiles allowed to watch or monitor.
#
# Optional. Default: [].
#
# Allowed values: (TODO: pendng)
#
:logs => [
'/home/blackstack/code1/master/app.log',
...
],
# List of websites published on this node.
# This is used for monitoring.
#
# Optional. Default: [].
#
# Allowed values: (TODO: pendng)
#
:webs => [
{
# descriptive name of this website.
:name => 'ruby-sinatra',
# port this website is listening.
:port => 3000,
# protocol used. Allowed values are [:http, :https].
:protocol => :http,
}, {
# descriptive name of this website.
:name => 'nginx',
# port this website is listening.
:port => 443,
# protocol used. Allowed values are [:http, :https].
:protocol => :https,
}
],
...
Requirement
Create status method
BlackStack::Deployer.add_node
that validates the format of the hash descriptor before creating an instance ofBlackStack::Infrastructure::Node
and add it to the@@nodes
array.