Home

Awesome

System overview

<picture> <img alt="Test Coverage" src="https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/andrewlukoshko/082466afa48717ae249ff072a0db02a3/raw/coverage-badge.json"> </picture> <br/><br/>

AlmaLinux Build System Web-Server (albs-web-server) is designed to control multiple Build System's processes like build, sign and release packages. Web-Server maintains the following functionality:

Mentioned tools and libraries are required for ALBS Web-Server to run in the current state:

Config

This config file is needed for the Web-Server to launch gitea-listener:

---
mqtt_queue_host: mosquitto
mqtt_queue_port: 1883
mqtt_queue_topic_unmodified: gitea-webhooks-unmodified
mqtt_queue_topic_modified: gitea-webhooks-modified
mqtt_queue_qos: 2
mqtt_client_id: albs_gitea_listener
mqtt_queue_username:
mqtt_queue_password:
mqtt_queue_clean_session: False
albs_jwt_token:
albs_address: http://web_server:8080

Running docker-compose

You can start the system using the Docker Compose tool.

Pre-requisites:

To start the system, run the following command: docker-compose up -d. To rebuild images after your local changes, just run docker-compose up -d --build.

In case you are building containers for the first time, there is how it should be done:

#!/bin/bash

set -e pipefail

mkdir -p ../volumes/pulp/settings

echo "CONTENT_ORIGIN='http://pulp'
ANSIBLE_API_HOSTNAME='http://pulp'
ANSIBLE_CONTENT_HOSTNAME='http://pulp/pulp/content'
TOKEN_AUTH_DISABLED=True" >> ../volumes/pulp/settings/settings.py

docker-compose up -d --build --force-recreate --remove-orphans
sleep 25
docker exec -it albs-web-server_pulp_1 bash -c 'pulpcore-manager reset-admin-password --password="admin"'

Scheduling tasks

Web-server works with multiple parts of the Build System. Web-server works with API requests that are divided by usage.

Build-node

POST /ping endpoint accepts the following payload:

{
  node_status: { 
    active_tasks: list # accepts a list of integer values;
  } 
}

POST /build_done endpoint accepts the following payload:

{
  build_done: {
    task_id: integer # accepts a integer value;
    status: string # accepts literal values that are 'done', 'failed', 'excluded';
    artifacts: {
     name: string # accepts a string value; 
     type: string # accepts literal values that are 'rpm', 'build_log';
     href: string # accepts a string value;
    }     
  }
}

POST /get_task endpoint accepts the following payload:

{
  request: {
     supported_arches: list # accepts a list of string values;
  }
}

This endpoint has a response model that returns information about the platform:

{
  id: integer # accepts an integer value;
  arch: string # accepts a string value;
  ref: {
    url: string # accepts a string value;
    git_ref: accepts an optional string value # it's an optional value that allows being absent;
  }
  platform: {
    name: string # accepts a string value;
    type: string # accepts literal values that are 'rpm', 'deb';
    data: dictrionary # dictionary, where a key should be a string while a value could be of any type;
  }
  created_by: {
    name: string # accepts a string value;
    email: string # accepts a string value;
  }
  repositories: string # accepts a list of string values that are 'name' and 'url'; 
  linked_builds: accepts a list of integer values # it's an optional value that allows being absent;
}

Builds

POST / endpoint accepts the following payload:

{
  build: {
    platforms: { # check that a list has at least one item; 
      name: string # accepts a string value;
      arch_list: list # accepts a list of string values;
    }
    tasks: { # check that a list has at least one item; 
      url: string # accepts a string value;
      git_ref: accepts an optional string value # it's an optional value that allows being absent;
    }
    linked_builds: accepts a list of integer values # it's an optional value that allows being absent;
  }
}

This endpoint has a response model that returns information about the platform:

{
  id: integer # accepts an integer value;
  created_at: datetime # accepts date time like year,month, etc;
  tasks: {
    id: integer # accepts an integer value;
    ts: accepts date time timestamp like year, month, etc # it's an optional value that allows being absent;
    status: integer # accepts an integer value;
    index: integer # accepts an integer value;
    arch: string #accepts a string value;
    platform: {
      id: integer # accepts an integer value;
      type: string # accepts a string value;
      name: string # accepts a string value;
      arch_list: list # accepts a list of string values;
    }
    ref: {
      url: string # accepts a string value;
      git_ref: accepts an optional string value # it's an optional value that allows being absent;
    }
    artifacts: {
      id: integer # accepts an integer value;
      name: string # accepts a string value;
      type: string # accepts a string value;
      href: string # accepts a string value;
    }
  } 
  user: {
    id: integer # accepts an integer value;
    username: string # accepts a string value;
    email: string # accepts a string value;
  }
  linked_builds: accepts a list of integer values # it's an optional value that allows being absent;
}

GET / this endpoint has a response model that returns one of the options. It can return a list of platforms:

{
  id: integer # accepts an integer value;
  created_at: datetime # accepts date time like year, month, etc;
  tasks: {
     id: integer # accepts a integer value;
     ts: accepts date time timestamp like year, month, etc # it's an optional value that allows to be absent;
     status: integer # accepts an integer value;
     index: integer # accepts an integer value;
     arch: string # accepts a string value;
     platform: {
       id: integer # accepts an integer value;
       type: string # accepts a string value;
       name: string # accepts a string value
       arch_list: list # accepts a list of a string values;
     }
     ref: {
       url: string # accepts a string value;
       git_ref: optional string value # it's an optional value that allows being absent;
     }
     artifacts: {
       id: integer # accepts an integer value;
       name: string # accepts a string value;
       type: string # accepts a string value;
       href: string # accepts a string value;
     }
  }
  user: {
     id: integer # accepts an integer value;
     username: string # accepts a string value;
     email: string # accepts a string value;
  }
  linked_builds: string value # it's an optional value that allows being absent;
}

or it can return the following information about the platform:

{
  builds: {
    id: integer # accepts an integer value;
    created_at: datetime # accepts date time like year, month, etc;
    tasks: {
      id: integer # accepts an integer value;
      ts: datetime timestamp like year, month, etc # it's an optional value that allows to be absent;
      status: integer # accepts an integer value;
      index: integer # accepts an integer value;
      arch: string # accepts a string value;
      platform: {
        id: integer # accepts an integer value;
        type: string # accepts a string value;
        name: string # accepts a string value
        arch_list: list # accepts a list of string values;
      }
     ref: {
       url: string # accepts a string value;
       git_ref: optional string value # it's an optional value that allows being absent;
     }
     artifacts: {
       id: integer # accepts an integer value;
       name: string # accepts a string value;
       type: string # accepts a string value;
       href: string # accepts a string value;
     }
   }
    user: {
      id: integer # accepts an integer value;
      username: string # accepts a string value;
      email: string # accepts a string value;
    }
    linked_builds: string value # it's an optional value that allows being absent;
  }
  total_builds: optional integer value # it's an optional value that allows being absent;
  current_page: optional integer value # it's an optional value that allows being absent;
}

GET /{build_id}/ endpoint accepts an integer value build_id . This endpoint has a response model that returns information about the platform:

{
  id: integer # accepts an integer value;
  created_at: datetime # accepts date time like year, month, etc;
  tasks: {
     id: integer # accepts an integer value;
     ts: date time timestamp like year, month, etc # it's an optional value that allows being absent;
     status: integer # accepts an integer value;
     index: integer # accepts an integer value;
     arch: string # accepts a string value;
     platform: {
       id: integer # acceptrs an integer value;
       type: string # accepts a string value;
       name: string # accepts a string value
       arch_list: list # accepts a list of string values;
     }
     ref: {
       url: string # accepts string value;
       git_ref: optional string value # it's an optional value that allows being absent;
     }
     artifacts: {
       id: integer # accepts an integer value;
       name: string # accepts a string value;
       type: string # accepts a string value;
       href: string # accepts a string value;
     }
  }
  user: {
     id: integer # accepts an integer value;
     username: string # accepts a string value;
     email: string # accepts a string value;
  }
  linked_builds: string value # it's an optional value that allows being absent;
}

PATCH /{build_id}/restart-failed endpoint accepts an integer value build_id. This endpoint has a response model that returns information about the platform:

{
  id: integer # accepts an integer value;
  created_at: datetime # accepts date time like year, month, etc;
  tasks: {
     id: integer # accepts an integer value;
     ts: date time timestamp like year, month, etc # it's an optional value that allows being absent;
     status: integer # accepts an integer value;
     index: integer # accepts an integer value;
     arch: string # accepts a string value;
     platform: {
       id: integer # acceptrs an integer value;
       type: string # accepts a string value;
       name: string # accepts a string value
       arch_list: list # accepts a list of string values;
     }
     ref: {
       url: string # accepts string value;
       git_ref: optional string value # it's an optional value that allows being absent;
     }
     artifacts: {
       id: integer # accepts an integer value;
       name: string # accepts a string value;
       type: string # accepts a string value;
       href: string # accepts a string value;
     }
  }
  user: {
     id: integer # accepts an integer value;
     username: string # accepts a string value;
     email: string # accepts a string value;
  }
  linked_builds: string value # it's an optional value that allows being absent;
}

DELETE /{build_id}/remove endpoint accepts an integer value build_id. This endpoint returns the '204' status code.

Distributions

POST / accepts the following payload:

{
  distribution: {
    name: string # accepts a string value;
    platforms: list # accepts a list of a string values; 
 }
}

This endpoint has a response model that returns information about the platform:

{
  id: integer # accepts an integer value;
  name: string # accepts a string value;
}

POST /add/{build_id}/{distribution}/ endpoint accepts a string distribution value and an integer build_id value. This endpoint has a response model that returns a dictionary, where the key should be a string while the value could be of boolean type.

POST /remove/{build_id}/{distribution}/ endpoint accepts a string distribution value and an integer build_id value. This endpoint has a response model that returns a dictionary, where the key should be a string while the value could be of boolean type.

GET / endpoint has a response model that returns the list of platforms:

{
  id: integer # accepts an integer value;
  name: string # accepts a string value;
}

Platforms

POST / endpoint accepts the following payload:

{
  name: string # accepts a string value;
  type: literal # accepts literal values that are 'rpm', 'deb';
  distr_type: string # accepts a string value;
  distr_version: string # accepts a string value;
  test_dist_name: string # accepts a string value
  arch_list: list # accepts a list of a string values; 
  repos: {
    name: string # aceppts a string value;
    arch: string # accepts a string value;
    url: string # accepts a string value;
    type: string # accepts a string value;
  }
  data: dictionary # dictionary with a key should be a string while a value could be any type.
}

This endpoint has a response model that returns information about the platform:

{
  id: integer # accepts an integer value;
  name: string # accepts a string value;
  arch_list: list # accepts list of a string values;
}

PUT / endpoint accepts the following payload:

{
  name: strint # accepts a string value;
  type: literal value that is 'rpm' or 'deb' # it's an optional value that allows being absent;
  distr_type: string value # it's an optional value that allows being absent;
  distr_version: string value # it's an optional value that allows being absent;
  arch_list: list of string values # it's an optional value that allows bein absent;
  repos: { # this is optional and allows being absent; 
    name: string # accepts a string value;
    arch: string # accepts a string value;
    url: string # accepts a string value;
    type: string # accepts a string value;
  }
  data: dictionary, where a key should be a string while a value could be of any type # it's an optional value that allows being absent;
}

This endpoint has a response model that returns information about the platform:

{
  id: integer # accepts an integer value;
  name: string # accepts a string value;
  arch_list: list # accepts a list of string values;
}

GET / endpoint has a response model that returns a list of platforms:

{
  id: integer # accepts an integer value;
  name: string # accepts a string value;
  arch_list: list # accepts a list of string values;
}

PATCH /{platform_id}/add-repositories endpoint has a response model that returns information about the platform:

{
  id: integer # accepts an integer value;
  name: string # accepts a string value;
  arch_list: list # accepts a list of string values;
}

PATCH /{platform_id}/remove-repositories endpoint has a response model that returns information about the platform:

{
  id: integer # accepts an integer value;
  name: string # accepts a string value;
  arch_list: list # accepts a list of string values;
}

Projects

GET /alma has a response model that returns a list of projects:

{
  name: string # accepts a string value;
  clone_url: string # accepts a string value;
  tags: list # accepts a list of string values; 
  branches: list # accepts a list of string values;
}

GET /alma/modularity endpoint has a response model that returns a list of projects:

{
  name: string # accepts a string value;
  clone_url: string # accepts a string value;
  tags: list # accepts a list of string values; 
  branches: list # accepts a list of string values;
}

Releases

GET / has a response model that returns a list of releases:

{   id: integer # accepts an integer value;
    status: integer # accepts an integer value;
    build_ids: list # accepts a list of integer values;
    plan: dictionary, where the key should be a string while value can be of any type # it's an optional value that allows being absent;
    created_by: {
        id: integer # accepts an integer value;
        username: string # accepts a string value;
        email: string # accepts a string value;
    }
}

POST /new/ endpoint accepts the following payload:

{
  builds: list # accepts a list of integer values;
  platform_id: integer # accepts an integer value;
  reference_platform_id: integer # accepts an integer value;
}

This endpoint has a response model that returns information about the release:

{   id: integer # accepts an integer value;
    status: integer # accepts an integer value;
    build_ids: list # accepts a list of integer values;
    plan: dictionary, where the key should be a string while value can be of any type # it's an optional value that allows being absent;
    created_by: {
        id: integer # accepts an integer value;
        username: string # accepts a string value;
        email: string # accepts a string value;
    }
}

PUT /{release_id}/ endpoint accepts an integer value release_id and the following payload:

{
  builds: optional list value # accepts a list of integer values;
  plan:  dictionary, where the key should be a string while value can be of any type # it's an optional value that allows being absent;
}

This endpoint has a response model that returns information about the release:

{   id: integer # accepts an integer value;
    status: integer # accepts an integer value;
    build_ids: list # accepts a list of integer values;
    plan: dictionary, where the key should be a string while value can be of any type # it's an optional value that allows being absent;
    created_by: {
        id: integer # accepts an integer value;
        username: string # accepts a string value;
        email: string # accepts a string value;
    }
}

POST /{release_id}/commit/ endpoint accepts an integer value release_id. This endpoint has a response model that returns the result of the release commit:

{
  release: {
    id: integer # accepts an integer value;
    status: integer # accepts an integer value;
    build_ids: list # accepts a list of integer values;
    plan: dictionary, where key should be a string while value can be of any type # it's an optional value that allows being absent;
    created_by: {
        id: integer # accepts an integer value;
        username: string # accepts a string value;
        email: string # accepts a string value;
    }
}
  message: string # accepts a string value;
}

Repositories

GET / endpoint has a response model that returns a list of repositories:

{
  id: integer # accepts an integer value;
  name: string # accepts a string value;
  arch: string # accepts a string value;
  url: string # accepts a string  value;
  type: string # accepts a string value;
  debug: optional boolean value # it's an optional value that allows being absent;
  production: optional boolean value # it's an optional value that allows being absent;
  pulp_href: optional boolean value # it's an optional value that allows being absent;
}

GET /{repository_id}/ endpoint accepts an integer value repository_id. This endpoint has a response model that returns information about the repository or 'None':

{
  id: integer # accepts an integer value;
  name: string # accepts a string value;
  arch: string # accepts a string value;
  url: string # accepts a string  value;
  type: string # accepts a string value;
  debug: optional boolean value # it's an optional value that allows being absent;
  production: optional boolean value # it's an optional value that allows being absent;
  pulp_href: optional boolean value # it's an optional value that allows being absent;
}

Sign key

GET / endpoint has a response model that returns a list of sign keys:

{
    id: integer # accepts an integer value;
    name: string # accepts a string value;
    description: string # accepts a string value;
    keyid: string # accepts a string value;
    public_url: string # accepts a string value;
    inserted: datetime # accepts date time like year, month, etc;
}

POST /new/ endpoint accepts the following payload:

{
    name: string # accepts a string value;
    description: string # accepts a string value;
    keyid: string # accepts a string value;
    fingerprint: string # accepts a string value;
    public_url: string # accepts a string value;
}

This endpoint has a response model that returns information about the sign key:

{
    id: integer # accepts an integer value;
    name: string # accepts a string value;
    description: string # accepts a string value;
    keyid: string # accepts a string value;
    public_url: string # accepts a string value;
    inserted: datetime # accepts date time like year, month, etc;
}

PUT /{sign_key_id/ endpoint accepts an integer value sign_key_id and the following payload:

{
    name: string value # it's an optional value that allows being absent;
    description: string value # it's an optional value that allows being absent;
    keyid: string value # it's an optional value that allows being absent;
    fingerprint: string value # it's an optional value that allows being absent;
    public_url: string value # it's an optional value that allows being absent;
}

This endpoint has a response model that returns information about the sign key:

{
    id: integer # accepts an integer value;
    name: string # accepts a string value;
    description: string # accepts a string value;
    keyid: string # accepts a string value;
    public_url: string # accepts a string value;
    inserted: datetime # accepts date time like year, month, etc;
}

Sign task

GET / endpoint accepts an integer value build_id. This endpoint has a response model that returns the list of sign tasks:

{
    id: integer # accepts an integer value;
    build_id: integer # accepts an integer value;
    sign_key: {
        id: integer # accepts an integer value;
        name: string # accepts a string value;
        description: string # accepts a string value;
        keyid: string # accepts a string value;
        public_url: string # accepts a string value;
        inserted: datetime # accepts date time like year, month, etc;
    }
    status: integer # accepts an integer value;
    error_message: string value # it's an optional value that allows being absent;
    log_href: string value # it's an optional value that allows being absent;
}

POST / endpoint accepts the following payload:

{
    build_id: integer # accepts an integer value;
    sign_key_id: integer # accepts an integer value;
}

This endpoint has a response model that returns the sign task:

{
    id: integer # accepts an integer value;
    build_id: integer # accepts an integer value;
    sign_key: {
        id: integer # accepts an integer value;
        name: string # accepts a string value;
        description: string # accepts a string value;
        keyid: string # accepts a string value;
        public_url: string # accepts a string value;
        inserted: datetime # accepts date time like year, month, etc;
    }
    status: integer # accepts an integer value;
    error_message: string value # it's an optional value that allows being absent;
    log_href: string value # it's an optional value that allows being absent;
}

POST /get_sign_task/ endpoint accepts the following payload:

{
    key_ids: string # accepts a list of string values;
}

This endpoint has a response model that returns a union of a dictionary with key and value of any type, and the information about available sign tasks:

{
    id: integer value # it's an optional value that allows being absent;
    build_id: integer value # it's an optional value that allows being absent;
    keyid: string value # it's an optional value that allows being absent;
    packages: {
        key_ids: a list of string values # it's an optional value that allows being absent;
    }
}

POST /{sign_task_id}/complete/ endpoint accepts an integer value sign_task_id and the following payload:

{
    build_id: integer # accepts an ingeter valut 
    success:  boolean # accepts a boolean value;
    error_message: string value # it's an optional value that allows being absent;
    log_href: string value # it's an optional value that allows being absent;
    packages: {
        key_ids: a list of string values # it's an optional value that allows being absent;
    }
}

This endpoint has a response model that returns information about the completed task:

{
    success: boolean # accepts a boolean value;
}

Tests

POST /{test_task_id}/result/ endpoint accepts an integer test_task_id value and the following payload:

{
  result: {
    api_version: string # accepts a string value;
    result: dictionary # a dictionary where key and value are of any type;
  }
}

PUT /build/{build_id}/restart endpoint accepts an integer build_id value.

PUT /build_task/{build_task_id}/restart endpoint accepts an integer build_task_id value.

GET /{build_task_id}/latest endpoint accepts an integer build_task_id value. This endpoint has a response model that returns a list of platforms:

{
  id: integer # accepts an integer value;
  package_name: string # accepts a string value;
  package_version: string # accepts a string value;
  package_release: string value # it's an optional value that allows being absent;
  status: integer # accepts an integer value;
  revision: integer # accepts an integer value;
  alts_response: dictionary # a dictionary where key and value are of any type;
}

GET /{build_task_id}/{revision} endpoint accepts an integer build_task_id value and an integer revision value. This endpoint has a response model that returns a list of platforms:

{
  id: integer # accepts an integer value;
  package_name: string # accepts a string value;
  package_version: string # accepts a string value;
  package_release: string value # it's an optional value that allows being absent;
  status: integer # accepts an integer value;
  revision: integer # accepts an integer value;
  alts_response: dictionary # a dictionary where key and value are of any type;
}

Users

POST /login/github endpoint accepts the following payload:

{
  user: {
    code: string # accepts a string value;
  }
}

This endpoint has a response model that returns information about the platform:

{
  id: integer # accepts an integer value;
  username: string # accepts a string value;
  email: string # accepts a string value;
  jwt_token: string # accepts a string value;
}

GET / endpoint has a response model that returns information about the platform:

  id: integer # accepts an integer value;
  username: string # accepts a string value;
  email: string # accepts a string value;

GET /all_user endpoint has a response model that returns information about users:

{
    id: integer # accepts an integer value;
    username: string # accepts a string value;
    email: string # accepts a string value;
}

Reporting issues

All issues should be reported to the Build System project.