diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/docs/VLAN.md b/docs/VLAN.md index f58a860b..36bf2453 100644 --- a/docs/VLAN.md +++ b/docs/VLAN.md @@ -16,9 +16,9 @@ the same network switch. There are two types of VLANs: - **Port-Based VLAN**: A VLAN is assigned to a particular port, and any machine - connected to that port automatically joins that VLAN + connected to that port automatically joins that VLAN. - **User-Based or Dynamic VLAN**: VLANs are assigned based on user - authentication or other dynamic criteria + authentication or other dynamic criteria. ## Network Architecture diff --git a/docs/ansible_docs.md b/docs/ansible_docs.md index 940e6e19..240a6f47 100644 --- a/docs/ansible_docs.md +++ b/docs/ansible_docs.md @@ -15,13 +15,13 @@ how to install Ansible here: Ansible provides several tools to facilitate server management: - **OpenSSH**: Used for setting up SSH and generating keys for server - authentication + authentication. - **Ad-hoc Commands**: Used as alternatives to playbooks for quick and simple - tasks + tasks. - **Playbooks**: YAML files containing specific tasks to manage servers, used - for complex tasks + for complex tasks. - **Inventory File**: Contains the list of servers grouped by categories for - organized management + organized management. ## How It Works @@ -31,8 +31,8 @@ Ansible relies on SSH to authenticate and configure servers. While you can use a single SSH key for managing all servers, it is often recommended to use two separate keys: -- One for personal SSH logins -- Another specifically for automation with Ansible +- One for personal SSH logins. +- Another specifically for automation with Ansible. #### Creation of SSH Keys @@ -72,9 +72,9 @@ For more details, see: Playbooks define the automation logic in a structured way. When you run a playbook, Ansible: -1. Loads temporary modules to the remote server -2. Executes the tasks (e.g., install packages, start services) -3. Removes the modules after execution +1. Loads temporary modules to the remote server. +2. Executes the tasks (e.g., install packages, start services). +3. Removes the modules after execution. For more details on playbooks: @@ -95,15 +95,15 @@ To learn more about ad-hoc commands, see: Ansible excels at server management by providing: - **Playbooks**: Makes task handover between teams seamless, as all required - tasks are documented in playbooks + tasks are documented in playbooks. - **Inventory Files**: Organizes server IP addresses by groups, making it easy - to manage and assign tasks + to manage and assign tasks. - **SSH Key**: Automates authentication, making server access and management - more efficient + more efficient. ## What If Ansible Becomes Outdated? -If Ansible becomes outdated or no longer maintained, other modern tools can be +If Ansible becomes outdated or is no longer maintained, other modern tools can be used for infrastructure automation and server management: - [Chef](https://docs.chef.io/manage/) diff --git a/mkdocs.yml b/mkdocs.yml old mode 100644 new mode 100755 diff --git a/playbooks/docs/glance-ansible_docs.md b/playbooks/docs/glance-ansible_docs.md new file mode 100644 index 00000000..a27dade4 --- /dev/null +++ b/playbooks/docs/glance-ansible_docs.md @@ -0,0 +1,416 @@ +# OpenStack Glance Deployment Using Ansible +### Comprehensive Documentation and Architecture Explanation + +--- + +## Table of Contents + +- [Introduction](#introduction) +- [OpenStack Architecture Context](#openstack-architecture-context) +- [Project Overview](#project-overview) +- [Pre-requisites and Environment](#pre-requisites-and-environment) +- [Project Structure](#project-structure) +- [Detailed Configuration Variables](#detailed-configuration-variables) +- [Role Breakdown and Workflow](#role-breakdown-and-workflow) + - [Keystone Role (Identity Service)](#keystone-role-identity-service) + - [Glance Role (Image Service)](#glance-role-image-service) +- [How the Ansible Playbook Operates](#how-the-ansible-playbook-operates) +- [Key Components and Concepts](#key-components-and-concepts) +- [Security Considerations](#security-considerations) +- [Post-Installation Verification](#post-installation-verification) +- [Extending and Customizing](#extending-and-customizing) +- [Troubleshooting Guide](#troubleshooting-guide) +- [References](#references) + +--- + +## Introduction + +This document details the automated installation and configuration of OpenStack's **Keystone** (identity service) and **Glance** (image service) components using Ansible. It provides a modular, idempotent, and reusable approach that simplifies deploying these critical cloud infrastructure services, ensuring they are correctly configured, secured, and integrated. + +--- + +## OpenStack Architecture Context + +OpenStack is composed of loosely coupled services that provide infrastructure-as-a-service (IaaS). Two essential components covered here are: + +- **Keystone:** The central authentication and authorization system. Every other OpenStack service depends on Keystone for identity management. +- **Glance:** The image service managing VM disk images used to provision instances. + +Glance requires Keystone to authenticate users and services securely. Therefore, Keystone must be installed and operational before deploying Glance. + +--- + +## Project Overview + +This Ansible project aims to: + +- **Automate installation** of Keystone and Glance along with their dependencies. +- **Configure database access** via MariaDB with securely managed credentials. +- **Set up Keystone** with secure tokens and proper Apache WSGI integration. +- **Configure Glance** to authenticate with Keystone and store images on local filesystem. +- **Register services and endpoints** in Keystone to enable integration across OpenStack components. +- **Deploy a minimal test image** to validate the Glance installation. + +--- + +## Pre-requisites and Environment + +- A fresh or clean **Ubuntu/Debian** system with root/sudo access. +- Ansible (version 2.9 or higher recommended) installed locally. +- Network connectivity to fetch packages and cloud images. +- Sufficient permissions to install packages, manage services, and configure Apache. + +--- + +## Project Structure + +The project follows best practices for Ansible roles, structured as: + +```text +glance-ansible/ +├── inventory.ini # Defines target hosts (default: localhost) +├── glance.yml # Main playbook orchestrating Keystone & Glance roles +└── roles/ + ├── keystone/ # Keystone role (identity service) + │ ├── defaults/main.yml # Default variables for Keystone + │ └── tasks/main.yml # Keystone installation & configuration steps + └── glance/ # Glance role (image service) + ├── defaults/main.yml # Default variables for Glance + └── tasks/main.yml # Glance installation & configuration steps +``` + +- `inventory.ini`: Defines target hosts (in this case, localhost as controller node). +- `glance.yml`: Main playbook invoking both Keystone and Glance roles in proper sequence. +- `roles/keystone`: Automates Keystone installation and configuration. +- `roles/glance`: Automates Glance installation and configuration, depending on Keystone. + +--- + +## Detailed Configuration Variables + +Each role contains default variables for easy customization: + +| Variable | Description | Default Value | +|----------------------------|--------------------------------------------------------------|----------------------| +| `mysql_root_password` | Root password for MariaDB/MySQL server | `newpassword` | +| `keystone_db_password` | Database password for Keystone's MySQL user | `keystone_db_pass` | +| `admin_token` | Initial Keystone admin token used internally during bootstrap | `ADMIN` | +| `controller_host` | Hostname/IP where OpenStack services run | `localhost` | +| `keystone_port` | HTTP port Keystone listens on | `5001` | +| `glance_db_pass` | Database password for Glance's MySQL user | `GlancePass123!` | +| `glance_user_pass` | Password for the Glance user within Keystone | `GlancePass123!` | +| `keystone_admin_pass` | Password used to bootstrap Keystone admin user | `admin` | + +> **Security Tip:** Replace default passwords with strong secrets before deploying to production. + +--- + +## Role Breakdown and Workflow + +### Keystone Role (Identity Service) + +**Purpose:** Set up Keystone to manage authentication for OpenStack. + +- **Package Installation:** Installs MariaDB, Keystone, Apache2, WSGI modules, and configuration helpers. +- **Database Setup:** Creates `keystone` database and user with restricted privileges. +- **Configuration:** Updates Keystone's config file with DB connection string, token provider (`fernet`), and admin token. +- **Database Sync:** Runs `keystone-manage db_sync` to create schema. +- **Key Setup:** Generates encryption keys for secure token management. +- **Bootstrap:** Initializes Keystone with admin credentials and endpoint URLs. +- **Apache Configuration:** Configures Apache with WSGI to serve Keystone on a dedicated port (`5001`). Ensures the site is enabled and Apache restarted. + +### Glance Role (Image Service) + +**Purpose:** Set up Glance for image management, relying on Keystone for authentication. + +- **Package Installation:** Installs Glance service, client tools, Apache2, WSGI modules, and utilities like `crudini` and `wget`. +- **Database Setup:** Ensures MariaDB root password is set; creates `glance` DB and user. +- **Configuration:** Configures `glance-api.conf` with DB connection and Keystone authentication details. +- **Database Sync:** Runs `glance-manage db_sync` to prepare database schema. +- **Service Management:** Enables and starts `glance-api` service. +- **Service Availability:** Polls Glance API endpoint until service is ready. +- **Keystone Integration:** + - Creates OpenStack user and service project if missing. + - Registers Glance service and API endpoints (public, internal, admin). +- **Image Upload:** Downloads Cirros test image and uploads it into Glance for verification. + +--- + +## How the Ansible Playbook Operates + +1. **Playbook Entry Point:** + The playbook (`glance.yml`) runs on the controller host and applies Keystone role first, ensuring the identity service is ready. + +2. **Idempotency:** + All tasks are written to be idempotent, meaning repeated runs will not cause errors or redundant changes. + +3. **Sequential Execution:** + Glance role only runs after Keystone is installed and accessible, preventing race conditions and dependency failures. + +4. **Variable-driven Configuration:** + Passwords, hostnames, ports, and other parameters are abstracted into variables for easy environment adaptation. + +5. **Service Registration:** + OpenStack users, projects, services, and endpoints are registered via CLI commands executed with appropriate OpenStack environment variables exported dynamically. + +6. **Service Availability Checks:** + The playbook waits and checks for the Glance API endpoint to be responsive before proceeding to image upload, ensuring system readiness. + +--- + +## Key Components and Concepts + +- **MariaDB:** Backend database storing persistent data for Keystone and Glance. +- **Fernet Tokens:** Secure symmetric encryption tokens used by Keystone for identity tokens. +- **WSGI and Apache:** Web server and gateway interface to serve Keystone and Glance APIs. +- **`crudini`:** Command-line utility to modify `.ini` configuration files reliably. +- **OpenStack CLI (`openstack`):** Used for managing Keystone users, roles, services, and images. +- **Cirros Image:** Minimal cloud image used as a functional test for the Glance service. + +--- + +## Security Considerations + +- Change default passwords before deploying in production environments. +- Protect the Keystone and Glance API endpoints using firewall rules and HTTPS with valid certificates. +- Secure MariaDB with restricted network access and strong authentication. +- Manage Fernet key rotations periodically to ensure token security. +- Limit user privileges to least required for operations. + +--- + +## Post-Installation Verification + +To verify a successful deployment: + +1. **Export OpenStack Credentials:** + +```bash +export OS_USERNAME=admin +export OS_PASSWORD=admin +export OS_PROJECT_NAME=admin +export OS_USER_DOMAIN_NAME=Default +export OS_PROJECT_DOMAIN_NAME=Default +export OS_AUTH_URL=http://localhost:5001/v3 +export OS_IDENTITY_API_VERSION=3 +``` +2. **Check Keystone Status** + +```bash +openstack token issue +``` + +3. **List Keystoone Image** + +``` +openstack image list +``` +# OpenStack Glance Deployment Using Ansible +### Comprehensive Documentation and Architecture Explanation + +--- + +## Table of Contents + +- [Introduction](#introduction) +- [OpenStack Architecture Context](#openstack-architecture-context) +- [Project Overview](#project-overview) +- [Pre-requisites and Environment](#pre-requisites-and-environment) +- [Project Structure](#project-structure) +- [Detailed Configuration Variables](#detailed-configuration-variables) +- [Role Breakdown and Workflow](#role-breakdown-and-workflow) + - [Keystone Role (Identity Service)](#keystone-role-identity-service) + - [Glance Role (Image Service)](#glance-role-image-service) +- [How the Ansible Playbook Operates](#how-the-ansible-playbook-operates) +- [Key Components and Concepts](#key-components-and-concepts) +- [Security Considerations](#security-considerations) +- [Post-Installation Verification](#post-installation-verification) +- [Extending and Customizing](#extending-and-customizing) +- [Troubleshooting Guide](#troubleshooting-guide) +- [References](#references) + +--- + +## Introduction + +This document details the automated installation and configuration of OpenStack's **Keystone** (identity service) and **Glance** (image service) components using Ansible. It provides a modular, idempotent, and reusable approach that simplifies deploying these critical cloud infrastructure services, ensuring they are correctly configured, secured, and integrated. + +--- + +## OpenStack Architecture Context + +OpenStack is composed of loosely coupled services that provide infrastructure-as-a-service (IaaS). Two essential components covered here are: + +- **Keystone:** The central authentication and authorization system. Every other OpenStack service depends on Keystone for identity management. +- **Glance:** The image service managing VM disk images used to provision instances. + +Glance requires Keystone to authenticate users and services securely. Therefore, Keystone must be installed and operational before deploying Glance. + +--- + +## Project Overview + +This Ansible project aims to: + +- **Automate installation** of Keystone and Glance along with their dependencies. +- **Configure database access** via MariaDB with securely managed credentials. +- **Set up Keystone** with secure tokens and proper Apache WSGI integration. +- **Configure Glance** to authenticate with Keystone and store images on local filesystem. +- **Register services and endpoints** in Keystone to enable integration across OpenStack components. +- **Deploy a minimal test image** to validate the Glance installation. + +--- + +## Pre-requisites and Environment + +- A fresh or clean **Ubuntu/Debian** system with root/sudo access. +- Ansible (version 2.9 or higher recommended) installed locally. +- Network connectivity to fetch packages and cloud images. +- Sufficient permissions to install packages, manage services, and configure Apache. + +--- + +## Project Structure + +The project follows best practices for Ansible roles, structured as: + +```text +glance-ansible/ +├── inventory.ini # Defines target hosts (default: localhost) +├── glance.yml # Main playbook orchestrating Keystone & Glance roles +└── roles/ + ├── keystone/ # Keystone role (identity service) + │ ├── defaults/main.yml # Default variables for Keystone + │ └── tasks/main.yml # Keystone installation & configuration steps + └── glance/ # Glance role (image service) + ├── defaults/main.yml # Default variables for Glance + └── tasks/main.yml # Glance installation & configuration steps +``` + +- `inventory.ini`: Defines target hosts (in this case, localhost as controller node). +- `glance.yml`: Main playbook invoking both Keystone and Glance roles in proper sequence. +- `roles/keystone`: Automates Keystone installation and configuration. +- `roles/glance`: Automates Glance installation and configuration, depending on Keystone. + +--- + +## Detailed Configuration Variables + +Each role contains default variables for easy customization: + +| Variable | Description | Default Value | +|----------------------------|--------------------------------------------------------------|----------------------| +| `mysql_root_password` | Root password for MariaDB/MySQL server | `newpassword` | +| `keystone_db_password` | Database password for Keystone's MySQL user | `keystone_db_pass` | +| `admin_token` | Initial Keystone admin token used internally during bootstrap | `ADMIN` | +| `controller_host` | Hostname/IP where OpenStack services run | `localhost` | +| `keystone_port` | HTTP port Keystone listens on | `5001` | +| `glance_db_pass` | Database password for Glance's MySQL user | `GlancePass123!` | +| `glance_user_pass` | Password for the Glance user within Keystone | `GlancePass123!` | +| `keystone_admin_pass` | Password used to bootstrap Keystone admin user | `admin` | + +> **Security Tip:** Replace default passwords with strong secrets before deploying to production. + +--- + +## Role Breakdown and Workflow + +### Keystone Role (Identity Service) + +**Purpose:** Set up Keystone to manage authentication for OpenStack. + +- **Package Installation:** Installs MariaDB, Keystone, Apache2, WSGI modules, and configuration helpers. +- **Database Setup:** Creates `keystone` database and user with restricted privileges. +- **Configuration:** Updates Keystone's config file with DB connection string, token provider (`fernet`), and admin token. +- **Database Sync:** Runs `keystone-manage db_sync` to create schema. +- **Key Setup:** Generates encryption keys for secure token management. +- **Bootstrap:** Initializes Keystone with admin credentials and endpoint URLs. +- **Apache Configuration:** Configures Apache with WSGI to serve Keystone on a dedicated port (`5001`). Ensures the site is enabled and Apache restarted. + +### Glance Role (Image Service) + +**Purpose:** Set up Glance for image management, relying on Keystone for authentication. + +- **Package Installation:** Installs Glance service, client tools, Apache2, WSGI modules, and utilities like `crudini` and `wget`. +- **Database Setup:** Ensures MariaDB root password is set; creates `glance` DB and user. +- **Configuration:** Configures `glance-api.conf` with DB connection and Keystone authentication details. +- **Database Sync:** Runs `glance-manage db_sync` to prepare database schema. +- **Service Management:** Enables and starts `glance-api` service. +- **Service Availability:** Polls Glance API endpoint until service is ready. +- **Keystone Integration:** + - Creates OpenStack user and service project if missing. + - Registers Glance service and API endpoints (public, internal, admin). +- **Image Upload:** Downloads Cirros test image and uploads it into Glance for verification. + +--- + +## How the Ansible Playbook Operates + +1. **Playbook Entry Point:** + The playbook (`glance.yml`) runs on the controller host and applies Keystone role first, ensuring the identity service is ready. + +2. **Idempotency:** + All tasks are written to be idempotent, meaning repeated runs will not cause errors or redundant changes. + +3. **Sequential Execution:** + Glance role only runs after Keystone is installed and accessible, preventing race conditions and dependency failures. + +4. **Variable-driven Configuration:** + Passwords, hostnames, ports, and other parameters are abstracted into variables for easy environment adaptation. + +5. **Service Registration:** + OpenStack users, projects, services, and endpoints are registered via CLI commands executed with appropriate OpenStack environment variables exported dynamically. + +6. **Service Availability Checks:** + The playbook waits and checks for the Glance API endpoint to be responsive before proceeding to image upload, ensuring system readiness. + +--- + +## Key Components and Concepts + +- **MariaDB:** Backend database storing persistent data for Keystone and Glance. +- **Fernet Tokens:** Secure symmetric encryption tokens used by Keystone for identity tokens. +- **WSGI and Apache:** Web server and gateway interface to serve Keystone and Glance APIs. +- **`crudini`:** Command-line utility to modify `.ini` configuration files reliably. +- **OpenStack CLI (`openstack`):** Used for managing Keystone users, roles, services, and images. +- **Cirros Image:** Minimal cloud image used as a functional test for the Glance service. + +--- + +## Security Considerations + +- Change default passwords before deploying in production environments. +- Protect the Keystone and Glance API endpoints using firewall rules and HTTPS with valid certificates. +- Secure MariaDB with restricted network access and strong authentication. +- Manage Fernet key rotations periodically to ensure token security. +- Limit user privileges to least required for operations. + +--- + +## Post-Installation Verification + +To verify a successful deployment: + +1. **Export OpenStack Credentials:** + +```bash +export OS_USERNAME=admin +export OS_PASSWORD=admin +export OS_PROJECT_NAME=admin +export OS_USER_DOMAIN_NAME=Default +export OS_PROJECT_DOMAIN_NAME=Default +export OS_AUTH_URL=http://localhost:5001/v3 +export OS_IDENTITY_API_VERSION=3 +``` +2. **Check Keystone Status** + +```bash +openstack token issue +``` + +3. **List Keystoone Image** + +``` +openstack image list +``` \ No newline at end of file diff --git a/playbooks/glance-ansible/ansible.cfg b/playbooks/glance-ansible/ansible.cfg new file mode 100644 index 00000000..d8bfc4fe --- /dev/null +++ b/playbooks/glance-ansible/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +inventory = inventory.ini +host_key_checking = False +retry_files_enabled = False diff --git a/playbooks/glance-ansible/glance.md b/playbooks/glance-ansible/glance.md new file mode 100644 index 00000000..192127b0 --- /dev/null +++ b/playbooks/glance-ansible/glance.md @@ -0,0 +1,175 @@ +# OpenStack Keystone + Glance Installation (Ansible-Based) + +This documentation describes a fully automated installation of **Keystone** (Identity Service) and **Glance** (Image Service) using **Ansible**. The playbook provisions and configures required services, sets up databases, initializes Keystone, registers Glance, and validates the image upload process. + +--- + +## Project Layout + +``` +├── ansible.cfg +├── group_vars +│   └── all.yml +├── inventory.ini +├── playbook.yml +└── roles + ├── glance + │   ├── tasks + │   │   └── main.yml + │   ├── templates + │      ├── glance-api-paste.ini.j2 + │      └── glance-api.conf.j2 + │   + ├── keystone + │   ├── tasks + │   │   └── main.yml + │   ├── templates + │       └── wsgi-keystone.conf.j2 + │  + └── test-setup + ├── tasks + │   └── main.yml + └── vars + └── main.yml +``` +--- + +## ⚙️ Variable Configuration (`group_vars/all.yml`) + +```yaml +# Database passwords +mysql_root_pass: newpassword +keystone_db_pass: keystone_db_pass +glance_db_pass: GlancePass123! + +# Keystone admin credentials +keystone_admin_pass: admin + +# Glance user password +glance_user_pass: GlancePass123! + +# Host and ports +controller_host: localhost +keystone_port: 5001 + +# Glance test image config +image_file: cirros-0.6.2-x86_64-disk.img +image_name: test-cirros +disk_format: qcow2 +container_format: bare + +# Keystone/Glance endpoints +keystone_url: http://localhost:5001/v3 +glance_url: http://localhost:9292/v2 + +# Keystone auth scope +admin_user: admin +admin_pass: admin +project_name: admin +domain_name: Default +``` + +--- + +## Keystone Installation (`roles/keystone/tasks/main.yml`) + +### Packages + +- Installs: MariaDB, Apache2, WSGI, Memcached, Keystone, OpenStack client, Python packages + +### MariaDB Configuration + +- Ensures `bind-address = 127.0.0.1` +- Creates `keystone` database +- Grants privileges to `keystone` user (for `localhost` and `%`) + +### Keystone Config + +- Configures `keystone.conf`: + - `[database]` connection string + - `[token]` provider = `fernet` +- Runs: + - `keystone-manage fernet_setup` + - `keystone-manage credential_setup` + - `keystone-manage db_sync` + - `keystone-manage bootstrap` + +### Apache WSGI + +- Adds Keystone virtual host on port `5001` +- Enables the site and restarts Apache + +--- + +## Glance Installation (`roles/glance/tasks/main.yml`) + +### Database + +- Creates `glance` database +- Grants user privileges for `glance` user + +### Configuration + +- Renders `glance-api.conf` and `glance-api-paste.ini` from templates +- Sets ownership to `glance:glance`, mode `0640` +- Runs `glance-manage db_sync` + +### Service Setup + +- Enables and restarts `glance-api` systemd service + +### Keystone Integration + +- Creates: + - `service` project + - `glance` user + - Role binding: `glance` as `admin` in `service` +- Registers Glance: + - Service type: `image` + - Endpoints: `public`, `internal`, `admin` at `http://localhost:9292` + +--- + +## Validation (`roles/test-setup/tasks/main.yml`) + +### Authentication + +- Sends `POST /v3/auth/tokens` to Keystone +- Extracts `X-Subject-Token` as auth token + +### Glance API Check + +- Polls `GET /images` until 200 OK is received + +### Cirros Image Upload + +1. Downloads image if missing +2. Sends metadata via `POST /images` +3. Extracts image `id` from response +4. Uploads binary using `PUT /images//file` +5. Lists images with `GET /images` +6. Deletes test image using `DELETE /images/` + +--- + +## Troubleshooting + +| Issue | Cause | Fix | +|-------|-------|-----| +| **403 Forbidden on Keystone** | Apache WSGI misconfigured | Ensure `Require all granted` in VirtualHost | +| **Image upload fails** | Bad image ID or Glance not ready | Confirm metadata created and Glance is running | +| **Token missing** | Wrong credentials or Keystone unreachable | Double-check `keystone_url` and auth info | +| **DB connection error** | Wrong password or bind-address issue | Check MariaDB logs and config | + +--- + +## Expected Results + +After running the playbook: + +- Keystone is reachable at: `http://localhost:5001/v3` +- Glance is reachable at: `http://localhost:9292/v2` +- Keystone admin and Glance service users are functional +- Cirros image is uploaded and deleted via Glance API + + diff --git a/playbooks/glance-ansible/glance.yaml b/playbooks/glance-ansible/glance.yaml new file mode 100644 index 00000000..3d9aef3c --- /dev/null +++ b/playbooks/glance-ansible/glance.yaml @@ -0,0 +1,6 @@ +- name: Deploy OpenStack Keystone and Glance + hosts: controller + become: true + roles: + - keystone + - glance \ No newline at end of file diff --git a/playbooks/glance-ansible/group_vars/all.yml b/playbooks/glance-ansible/group_vars/all.yml new file mode 100644 index 00000000..fa66147c --- /dev/null +++ b/playbooks/glance-ansible/group_vars/all.yml @@ -0,0 +1,8 @@ +mysql_root_pass: "newpassword" +keystone_db_pass: "keystone_db_pass" +keystone_admin_pass: "admin" +admin_token: "ADMIN" +glance_db_pass: "GlancePass123!" +glance_user_pass: "GlancePass123!" +controller_host: "localhost" +keystone_port: 5001 diff --git a/playbooks/glance-ansible/inventory.ini b/playbooks/glance-ansible/inventory.ini new file mode 100644 index 00000000..df8b5f69 --- /dev/null +++ b/playbooks/glance-ansible/inventory.ini @@ -0,0 +1,2 @@ +[all] +localhost ansible_connection=local diff --git a/playbooks/glance-ansible/playbook.yml b/playbooks/glance-ansible/playbook.yml new file mode 100644 index 00000000..e9297f43 --- /dev/null +++ b/playbooks/glance-ansible/playbook.yml @@ -0,0 +1,10 @@ +--- +- name: Setup OpenStack Keystone, Glance and Test + hosts: all + connection: local + become: true + + roles: + - keystone + - glance + - test-setup diff --git a/playbooks/glance-ansible/roles/glance/defaults/main.yaml b/playbooks/glance-ansible/roles/glance/defaults/main.yaml new file mode 100644 index 00000000..a0d0573a --- /dev/null +++ b/playbooks/glance-ansible/roles/glance/defaults/main.yaml @@ -0,0 +1,7 @@ +--- +new_mysql_root_pass: newpassword +glance_db_pass: GlancePass123! +glance_user_pass: GlancePass123! +controller_host: localhost +keystone_port: 5001 +keystone_admin_pass: admin diff --git a/playbooks/glance-ansible/roles/glance/tasks/main.yml b/playbooks/glance-ansible/roles/glance/tasks/main.yml new file mode 100644 index 00000000..eac79e83 --- /dev/null +++ b/playbooks/glance-ansible/roles/glance/tasks/main.yml @@ -0,0 +1,220 @@ +--- +- name: Install Glance and Keystone dependencies + apt: + name: + - mariadb-server + - apache2 + - libapache2-mod-wsgi-py3 + - python3-pymysql + - python3-openstackclient + - python3-keystone + - keystone + - glance + - python3-glanceclient + - crudini + - memcached + - curl + state: present + update_cache: true + +- name: Ensure MariaDB bind-address is set to 127.0.0.1 + lineinfile: + path: /etc/mysql/mariadb.conf.d/50-server.cnf + regexp: '^bind-address' + line: 'bind-address = 127.0.0.1' + +- name: Restart MariaDB after bind-address fix + systemd: + name: mariadb + state: restarted + +- name: Ensure Apache listens on Keystone port + lineinfile: + path: /etc/apache2/ports.conf + line: "Listen {{ keystone_port }}" + state: present + +- name: Configure Keystone Apache site for port {{ keystone_port }} + copy: + dest: /etc/apache2/sites-available/keystone.conf + content: | + + WSGIDaemonProcess keystone user=keystone group=keystone processes=5 threads=1 + WSGIProcessGroup keystone + WSGIScriptAlias / /usr/bin/keystone-wsgi-public + + Require all granted + + ErrorLog /var/log/apache2/keystone_error.log + CustomLog /var/log/apache2/keystone_access.log combined + + +- name: Enable Keystone Apache site + command: a2ensite keystone + ignore_errors: true + +- name: Restart Apache after Keystone site enable + systemd: + name: apache2 + state: restarted + +- name: Drop and create Keystone DB to force repair + mysql_db: + name: keystone + state: absent + login_user: root + login_password: "{{ mysql_root_pass }}" + ignore_errors: true + +- name: Create Keystone database + mysql_db: + name: keystone + state: present + login_user: root + login_password: "{{ mysql_root_pass }}" + +- name: Grant Keystone DB user privileges + mysql_user: + name: keystone + password: "{{ keystone_db_pass }}" + priv: 'keystone.*:ALL' + host: localhost + state: present + login_user: root + login_password: "{{ mysql_root_pass }}" + +- name: Grant Keystone DB user privileges for any host + mysql_user: + name: keystone + password: "{{ keystone_db_pass }}" + priv: 'keystone.*:ALL' + host: '%' + state: present + login_user: root + login_password: "{{ mysql_root_pass }}" + +- name: Configure Keystone DB connection + command: crudini --set /etc/keystone/keystone.conf database connection "mysql+pymysql://keystone:{{ keystone_db_pass }}@localhost/keystone" + +- name: Configure Keystone token provider + command: crudini --set /etc/keystone/keystone.conf token provider fernet + +- name: Setup fernet keys and credentials for Keystone + command: keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone + +- name: Credential setup for Keystone + command: keystone-manage credential_setup --keystone-user keystone --keystone-group keystone + +- name: Sync Keystone DB + command: keystone-manage db_sync + +- name: Bootstrap Keystone + command: > + keystone-manage bootstrap + --bootstrap-password {{ keystone_admin_pass }} + --bootstrap-admin-url http://{{ controller_host }}:{{ keystone_port }}/v3/ + --bootstrap-internal-url http://{{ controller_host }}:{{ keystone_port }}/v3/ + --bootstrap-public-url http://{{ controller_host }}:{{ keystone_port }}/v3/ + --bootstrap-region-id RegionOne + +- name: Wait for Keystone to be reachable + uri: + url: http://{{ controller_host }}:{{ keystone_port }}/v3 + method: GET + status_code: 200 + return_content: no + register: keystone_status + retries: 10 + delay: 3 + until: keystone_status.status == 200 + +- name: Set OpenStack environment facts + set_fact: + os_auth: + OS_USERNAME: admin + OS_PASSWORD: "{{ keystone_admin_pass }}" + OS_PROJECT_NAME: admin + OS_USER_DOMAIN_NAME: Default + OS_PROJECT_DOMAIN_NAME: Default + OS_AUTH_URL: http://{{ controller_host }}:{{ keystone_port }}/v3 + OS_IDENTITY_API_VERSION: 3 + +- name: Create Glance database + mysql_db: + name: glance + state: present + login_user: root + login_password: "{{ mysql_root_pass }}" + +- name: Create Glance DB user localhost + mysql_user: + name: glance + password: "{{ glance_db_pass }}" + priv: "glance.*:ALL" + host: localhost + state: present + login_user: root + login_password: "{{ mysql_root_pass }}" + +- name: Create Glance DB user any host + mysql_user: + name: glance + password: "{{ glance_db_pass }}" + priv: "glance.*:ALL" + host: "%" + state: present + login_user: root + login_password: "{{ mysql_root_pass }}" + +- name: Configure glance-api.conf + template: + src: glance-api.conf.j2 + dest: /etc/glance/glance-api.conf + +- name: Configure glance-api-paste.ini + template: + src: glance-api-paste.ini.j2 + dest: /etc/glance/glance-api-paste.ini + +- name: Set permissions on glance config files + file: + path: "{{ item }}" + owner: glance + group: glance + mode: 0640 + loop: + - /etc/glance/glance-api.conf + - /etc/glance/glance-api-paste.ini + +- name: Sync Glance DB + command: glance-manage --config-file /etc/glance/glance-api.conf db_sync + +- name: Enable and restart glance-api service + systemd: + name: glance-api + enabled: yes + state: restarted + +- name: Create service project + shell: openstack project show service || openstack project create --domain default --description "Service Project" service + environment: "{{ os_auth }}" + +- name: Create Glance user + shell: openstack user show glance || openstack user create --domain default --password "{{ glance_user_pass }}" glance + environment: "{{ os_auth }}" + +- name: Assign admin role to Glance user + shell: openstack role add --project service --user glance admin || true + environment: "{{ os_auth }}" + +- name: Register Glance service + shell: openstack service show glance || openstack service create --name glance --description "OpenStack Image" image + environment: "{{ os_auth }}" + +- name: Register Glance endpoints + shell: | + for iface in public internal admin; do + openstack endpoint list --service glance --interface $iface | grep -q glance || \ + openstack endpoint create --region RegionOne image $iface http://localhost:9292 + done + environment: "{{ os_auth }}" diff --git a/playbooks/glance-ansible/roles/glance/templates/glance-api-paste.ini.j2 b/playbooks/glance-ansible/roles/glance/templates/glance-api-paste.ini.j2 new file mode 100644 index 00000000..cea98269 --- /dev/null +++ b/playbooks/glance-ansible/roles/glance/templates/glance-api-paste.ini.j2 @@ -0,0 +1,24 @@ +[composite:glance-api-keystone] +use = egg:Paste#urlmap +/v2: glance-api-pipeline + +[pipeline:glance-api-pipeline] +pipeline = authtoken context glance-api-app + +[app:glance-api-app] +paste.app_factory = glance.api.v2.router:API.factory + +[filter:authtoken] +paste.filter_factory = keystonemiddleware.auth_token:filter_factory +auth_uri = http://localhost:5001 +auth_url = http://localhost:5001 +memcached_servers = localhost:11211 +auth_type = password +project_domain_name = Default +user_domain_name = Default +project_name = service +username = glance +password = GlancePass123! + +[filter:context] +paste.filter_factory = glance.api.middleware.context:ContextMiddleware.factory diff --git a/playbooks/glance-ansible/roles/glance/templates/glance-api.conf.j2 b/playbooks/glance-ansible/roles/glance/templates/glance-api.conf.j2 new file mode 100644 index 00000000..0a45cd32 --- /dev/null +++ b/playbooks/glance-ansible/roles/glance/templates/glance-api.conf.j2 @@ -0,0 +1,20 @@ +[database] +connection = mysql+pymysql://glance:{{ glance_db_pass }}@localhost/glance + +[keystone_authtoken] +www_authenticate_uri = http://{{ controller_host }}:{{ keystone_port }} +auth_url = http://{{ controller_host }}:{{ keystone_port }} +memcached_servers = localhost:11211 +auth_type = password +project_domain_name = Default +user_domain_name = Default +project_name = service +username = glance +password = {{ glance_user_pass }} + +[paste_deploy] +flavor = keystone + +[DEFAULT] +debug = true +filesystem_store_datadir = /var/lib/glance/images/ diff --git a/playbooks/glance-ansible/roles/keystone/defaults/main.yaml b/playbooks/glance-ansible/roles/keystone/defaults/main.yaml new file mode 100644 index 00000000..79ade152 --- /dev/null +++ b/playbooks/glance-ansible/roles/keystone/defaults/main.yaml @@ -0,0 +1,6 @@ +--- +mysql_root_password: newpassword +keystone_db_password: keystone_db_pass +admin_token: ADMIN +controller_host: localhost +keystone_port: 5001 \ No newline at end of file diff --git a/playbooks/glance-ansible/roles/keystone/tasks/main.yml b/playbooks/glance-ansible/roles/keystone/tasks/main.yml new file mode 100644 index 00000000..79b2bebe --- /dev/null +++ b/playbooks/glance-ansible/roles/keystone/tasks/main.yml @@ -0,0 +1,99 @@ +--- +- name: Install Keystone dependencies + apt: + name: + - mariadb-server + - python3-pymysql + - keystone + - apache2 + - libapache2-mod-wsgi-py3 + - crudini + state: present + update_cache: true +- name: Ensure PyMySQL is installed in the virtualenv + pip: + name: PyMySQL + virtualenv: /home/ubuntu/project/openstack/playbooks/glance-ansible/venv + +- name: Ensure MariaDB is started and enabled + systemd: + name: mariadb + state: started + enabled: true + +- name: Set MySQL root password if not already set + shell: > + mysql -u root -e "SELECT 1;" && \ + mysql -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '{{ mysql_root_pass }}'; FLUSH PRIVILEGES;" || \ + mysql -u root -p"{{ mysql_root_pass }}" -e "SELECT 1;" + register: mysql_root_password_set + failed_when: mysql_root_password_set.rc != 0 and 'Access denied' in mysql_root_password_set.stderr + changed_when: "'ALTER USER' in mysql_root_password_set.stdout" + +- name: Create Keystone database + community.mysql.mysql_db: + name: keystone + state: present + login_user: root + login_password: "{{ mysql_root_pass }}" + +- name: Create Keystone DB user + community.mysql.mysql_user: + name: keystone + password: "{{ keystone_db_pass }}" + priv: "keystone.*:ALL" + host: "localhost" + state: present + login_user: root + login_password: "{{ mysql_root_pass }}" + +- name: Configure Keystone DB connection + command: crudini --set /etc/keystone/keystone.conf database connection "mysql+pymysql://keystone:{{ keystone_db_pass }}@localhost/keystone" + +- name: Configure Keystone token provider + command: crudini --set /etc/keystone/keystone.conf token provider fernet + +- name: Configure Keystone admin token + command: crudini --set /etc/keystone/keystone.conf DEFAULT admin_token "{{ admin_token }}" + +- name: Run Keystone DB sync + command: keystone-manage db_sync + +- name: Initialize fernet keys + command: keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone + +- name: Initialize credential keys + command: keystone-manage credential_setup --keystone-user keystone --keystone-group keystone + +- name: Bootstrap Keystone + command: > + keystone-manage bootstrap + --bootstrap-password {{ keystone_admin_pass }} + --bootstrap-admin-url http://{{ controller_host }}:{{ keystone_port }}/v3/ + --bootstrap-internal-url http://{{ controller_host }}:{{ keystone_port }}/v3/ + --bootstrap-public-url http://{{ controller_host }}:{{ keystone_port }}/v3/ + --bootstrap-region-id RegionOne + +- name: Ensure Apache listens on Keystone port + lineinfile: + path: /etc/apache2/ports.conf + line: "Listen {{ keystone_port }}" + state: present + +- name: Disable old Keystone site if exists + shell: a2dissite keystone.conf || true + ignore_errors: true + +- name: Deploy Keystone WSGI Apache config + template: + src: wsgi-keystone.conf.j2 + dest: /etc/apache2/sites-available/wsgi-keystone.conf + +- name: Enable Keystone site + command: a2ensite wsgi-keystone.conf + +- name: Restart Apache + systemd: + name: apache2 + state: restarted + enabled: true diff --git a/playbooks/glance-ansible/roles/keystone/templates/wsgi-keystone.conf.j2 b/playbooks/glance-ansible/roles/keystone/templates/wsgi-keystone.conf.j2 new file mode 100644 index 00000000..f170f43c --- /dev/null +++ b/playbooks/glance-ansible/roles/keystone/templates/wsgi-keystone.conf.j2 @@ -0,0 +1,8 @@ + + WSGIDaemonProcess keystone_wsgi processes=5 threads=1 user=keystone group=keystone display-name=%{GROUP} + WSGIProcessGroup keystone_wsgi + WSGIScriptAlias / /usr/bin/keystone-wsgi-public + ErrorLogFormat "%{cu}t %M" + ErrorLog /var/log/apache2/keystone_error.log + CustomLog /var/log/apache2/keystone_access.log combined + diff --git a/playbooks/glance-ansible/roles/test-setup/tasks/main.yml b/playbooks/glance-ansible/roles/test-setup/tasks/main.yml new file mode 100644 index 00000000..23f86f98 --- /dev/null +++ b/playbooks/glance-ansible/roles/test-setup/tasks/main.yml @@ -0,0 +1,106 @@ +--- +- name: Authenticate with Keystone to get token + shell: | + RESPONSE=$(curl -s -i -X POST "{{ keystone_url }}/auth/tokens" \ + -H "Content-Type: application/json" \ + -d '{ + "auth": { + "identity": { + "methods": ["password"], + "password": { + "user": { + "name": "{{ admin_user }}", + "domain": { "name": "{{ domain_name }}" }, + "password": "{{ admin_pass }}" + } + } + }, + "scope": { + "project": { + "name": "{{ project_name }}", + "domain": { "name": "{{ domain_name }}" } + } + } + } + }') + TOKEN=$(echo "$RESPONSE" | grep -i "X-Subject-Token:" | awk '{print $2}' | tr -d '\r') + echo "$TOKEN" + register: keystone_token + changed_when: false + +- name: Fail if Keystone token not received + fail: + msg: "Failed to get Keystone token" + when: keystone_token.stdout == "" + +- name: Wait for Glance API to be reachable + shell: | + RETRY=0 + while [ $RETRY -lt 10 ]; do + HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -H "X-Auth-Token: {{ keystone_token.stdout }}" "{{ glance_url }}/images") || HTTP_CODE="000" + if [ "$HTTP_CODE" = "200" ]; then + exit 0 + fi + sleep 3 + RETRY=$((RETRY + 1)) + done + exit 1 + register: glance_reachable + failed_when: glance_reachable.rc != 0 + changed_when: false + +- name: Download Cirros test image if missing + get_url: + url: "http://download.cirros-cloud.net/0.6.2/{{ image_file }}" + dest: "/tmp/{{ image_file }}" + mode: '0644' + when: not lookup('file', '/tmp/' + image_file, errors='ignore') + +- name: Create Glance image metadata + shell: | + curl -s -X POST "{{ glance_url }}/images" \ + -H "X-Auth-Token: {{ keystone_token.stdout }}" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "{{ image_name }}", + "disk_format": "{{ disk_format }}", + "container_format": "{{ container_format }}", + "visibility": "public" + }' + register: create_image_response + changed_when: false + +- name: Extract Image ID from create response + set_fact: + image_id: "{{ (create_image_response.stdout | from_json).id }}" + +- name: Fail if image ID not found + fail: + msg: "Failed to create image metadata." + when: image_id is not defined or image_id == "" + +- name: Upload image binary + shell: | + curl -s -X PUT "{{ glance_url }}/images/{{ image_id }}/file" \ + -H "X-Auth-Token: {{ keystone_token.stdout }}" \ + -H "Content-Type: application/octet-stream" \ + --data-binary "@/tmp/{{ image_file }}" + register: upload_image + failed_when: upload_image.rc != 0 + changed_when: false + +- name: Verify image list (prints JSON if jq available) + shell: | + if command -v jq >/dev/null 2>&1; then + curl -s -H "X-Auth-Token: {{ keystone_token.stdout }}" "{{ glance_url }}/images" | jq . + else + echo "Warning: jq not found, printing raw JSON" + curl -s -H "X-Auth-Token: {{ keystone_token.stdout }}" "{{ glance_url }}/images" + fi + register: image_list + changed_when: false + +- name: Delete test image + shell: | + curl -s -X DELETE "{{ glance_url }}/images/{{ image_id }}" -H "X-Auth-Token: {{ keystone_token.stdout }}" + changed_when: false diff --git a/playbooks/glance-ansible/roles/test-setup/vars/main.yml b/playbooks/glance-ansible/roles/test-setup/vars/main.yml new file mode 100644 index 00000000..a35ecdd4 --- /dev/null +++ b/playbooks/glance-ansible/roles/test-setup/vars/main.yml @@ -0,0 +1,10 @@ +keystone_url: "http://localhost:5001/v3" +glance_url: "http://localhost:9292/v2" +admin_user: "admin" +admin_pass: "admin" +project_name: "admin" +domain_name: "Default" +image_name: "test-cirros" +image_file: "cirros-0.6.2-x86_64-disk.img" +disk_format: "qcow2" +container_format: "bare" diff --git a/playbooks/glance-ansible/uninstall-key-glance.yml b/playbooks/glance-ansible/uninstall-key-glance.yml new file mode 100644 index 00000000..ca01d4df --- /dev/null +++ b/playbooks/glance-ansible/uninstall-key-glance.yml @@ -0,0 +1,82 @@ +--- +- name: Uninstall Keystone and Glance + hosts: all + become: true + tasks: + + - name: Stop Keystone and Glance services + systemd: + name: "{{ item }}" + state: stopped + enabled: false + loop: + - apache2 + - keystone + - glance-api + - glance-registry + ignore_errors: yes + + - name: Purge Keystone and Glance packages + apt: + name: + - keystone + - glance + - python3-keystone + - python3-glance + - python3-keystonemiddleware + - python3-glance-store + - apache2 + - libapache2-mod-wsgi-py3 + state: absent + purge: yes + autoremove: yes + update_cache: yes + + - name: Remove Keystone and Glance configuration directories + file: + path: "{{ item }}" + state: absent + loop: + - /etc/keystone + - /etc/glance + - /var/lib/keystone + - /var/lib/glance + - /var/log/keystone + - /var/log/glance + + - name: Drop Keystone and Glance MySQL databases (optional) + mysql_db: + name: "{{ item }}" + state: absent + login_user: root + login_password: "newpassword" + loop: + - keystone + - glance + + - name: Drop Keystone and Glance MySQL users (optional) + mysql_user: + name: "{{ item }}" + host: "localhost" + state: absent + login_user: root + login_password: "newpassword" + loop: + - keystone + - glance + + - name: Remove Keystone and Glance environment scripts + file: + path: "{{ item }}" + state: absent + loop: + - /root/keystonerc + - /root/admin-openrc + - /root/glancerc + - /etc/profile.d/keystone.sh + + - name: Clear Keystone and Glance from systemd journal logs (optional) + shell: | + journalctl --rotate + journalctl --vacuum-time=1s + when: ansible_facts['os_family'] == 'Debian' \ No newline at end of file