MassProspecting / docs

Public documentation, roadmap and issue tracker of MassProspecting
http://doc.massprospecting.com/
0 stars 0 forks source link

method `BlackStack::Deployment.add_node` #207

Closed leandrosardi closed 1 week ago

leandrosardi commented 1 week ago

Requirement

Create status method BlackStack::Deployer.add_node that validates the format of the hash descriptor before creating an instance of BlackStack::Infrastructure::Node and add it to the @@nodes array.

leandrosardi commented 1 week ago

GPT - Try 1

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.

leandrosardi commented 1 week ago

GPT - Try 1

Image

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
leandrosardi commented 1 week ago

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.

...
 # 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,
        }
    ],
...