Saturday, 8 August 2026

How to manage WSL and Ansible automation &Azure Devops

Introduction to DevOps - GeeksforGeeks


Question : How to install Oracle database


Oracle Database does not natively support Ubuntu Linux. 
Because Oracle only officially certifies Red Hat Enterprise Linux (RHEL) and Oracle Linux, installing it bare-metal on Ubuntu is a highly unstable "hack" prone to errors. The best practice for running Oracle Database on an Ubuntu Azure VM is to deploy it inside a Docker Container, utilizing Oracle's officially supported container images. 

Step 1: Configure Azure Network Security Group (NSG)
Before logging into your VM, you must open the standard Oracle communication port.
  1. Navigate to the Azure Portal and find your Ubuntu Virtual Machine.
  2. Under the left-hand menu, click Networking.
  3. Click Add inbound port rule.
  4. Set the Destination port ranges to 1521 and Protocol to TCP.
  5. Click Add to save. 

Step 2: Install Docker on the Ubuntu Azure VM
SSH into your Ubuntu VM and install the Docker engine. 
bash
# Update local package index
sudo apt-get update

# Install Docker
sudo apt-get install -y docker.io

# Start and enable the Docker service
sudo systemctl start docker
sudo systemctl enable docker
Step 3: Pull and Run the Oracle Database Container
You can pull an official pre-built Oracle Database image. For a lightweight and free option ideal for development, use the Oracle Database Express Edition (XE) or 23ai Free image. 
Run the following command to download the image and launch the container automatically: []
bash
sudo docker run -d \
  --name oracle23ai \
  -p 1521:1521 \
  -e ORACLE_PASSWORD=YourSecurePassword123 \
  ://oracle.com
Note: If you specifically require Enterprise Edition 19c, you can build or pull an image like banglamon/oracle193db:19.3.0-ee and map your variables accordingly. []
To monitor the logs and ensure the database initialization finishes successfully: []
bash
sudo docker logs -f oracle23ai
Look for the text DATABASE IS READY TO USE before proceeding. []

Step 4: Access SQL*Plus inside the Container
Once initialization completes, log directly into the running container to execute database commands. 
bash
# Access the container's bash environment
sudo docker exec -it oracle23ai bash

# Log into SQL*Plus as the System Administrator
sqlplus sys/YourSecurePassword123 as sysdba
Step 5: Test External Connection
You can now connect to your new Oracle Database from your local workstation using tools like Oracle SQL Developer or Toad. Use the following parameter configurations: 
  • Connection Type: Basic
  • Host: <Your_Azure_VM_Public_IP>
  • Port: 1521
  • Service Name / SID: FREE (or FREEPDB1 for the pluggable database. For 19c images, this is usually ORCL or SE).
  • Username: SYSTEM
  • Password: YourSecurePassword123 

A playbook is failing on a specific task. Describe your systematic approach to debugging the issue. What command-line flags and Ansible modules would you use?

To debug a failing Ansible task :

  1. Increase verbosity using -vvv to get detailed output.
  2. Isolate the issue with --limit and --start-at-task.
  3. Use debug and register to inspect variables and task output.
  4. Run in check mode with --check --diff to preview changes.

 How Can You Programmatically Access A Variable Name Within An Ansible Playbook?

To access a variable name programmatically within an Ansible playbook, setup the `set_fact` module with a task like:

- name: Extract variable name
   set_fact:
    var_name: "{{ my_variable | dict2items | selectattr('value', 'eq', my_value) | map(attribute='key') | first }}"

This task sets `var_name` based on the variable name corresponding to the specified value (`my_value`). Try on adjusting `my_variable` and `my_value` accordingly.

You have a playbook that takes an unacceptably long time to run against 500 hosts. What are the first three things you would investigate or tune to improve its performance?

To improve the performance of a slow playbook running against 500 hosts, I’d first investigate three key areas:

  1. Enable SSH Pipelining – Reduces overhead by reusing SSH connections, speeding up task execution.
  2. Increase Forks – Boosts parallelism by allowing Ansible to manage more hosts simultaneously (default is 5).
  3. Configure Fact Caching – Stores host facts to avoid re-gathering them on every run, saving time across large inventories.
Additional optimizations include using async tasks for long operations and the free strategy plugin to let hosts proceed independently.

Explain Ansible Inventory And Discuss Its Various Types.

Ansible Inventory is a collection of hosts (managed nodes) that Ansible targets during automation. It defines which machines to configure and how they are grouped.

Types of Inventory

  • Static Inventory
    Defined manually in an INI or YAML file.
  • Hosts and groups are explicitly listed.
  • Simple and ideal for small or stable environments.

Dynamic Inventory

  • Generated automatically using scripts or plugins.
  • Pulls host data from external sources like AWS, Azure, GCP, or CMDBs.
  • Ideal for cloud-native or large-scale environments with frequent changes.

 Can You Automate Password Input In An Ansible Playbook Using Encrypted Files?

Yes, you can automate password input in Ansible playbooks using encrypted files through Ansible Vault. Vault allows you to securely store sensitive data like passwords, API keys, or private credentials in encrypted YAML files. These files can be referenced in your playbooks just like regular variables, ensuring secure automation without exposing secrets in plain text. You can create a Vault file using:

ansible-vault create secrets.yml

Then include it in your playbook with vars_files, and unlock it during execution using --ask-vault-pass or --vault-password-file.

 Can You Automate Password Input In An Ansible Playbook Using Encrypted Files?

Yes, you can automate password input in Ansible playbooks using encrypted files through Ansible Vault. Vault allows you to securely store sensitive data like passwords, API keys, or private credentials in encrypted YAML files. These files can be referenced in your playbooks just like regular variables, ensuring secure automation without exposing secrets in plain text. You can create a Vault file using:

ansible-vault create secrets.yml

Then include it in your playbook with vars_files, and unlock it during execution using --ask-vault-pass or --vault-password-file.

 What Command Will You Use To Run An Ansible Playbook With a Specific Inventory File?

To run an Ansible playbook with a specific inventory file, use the ansible-playbook command with the -i option to specify the inventory.
Example:

ansible-playbook -i /path/to/inventory/file myplaybook.yml

Replace /path/to/inventory/file with the actual path to your inventory file and myplaybook.yml with your playbook name. The -i flag tells Ansible which inventory to use during execution.

Not all Ansible modules are inherently idempotent. How can a playbook author enforce idempotency when using modules like shell or command?

Modules like shell and command execute arbitrary commands without checking system state, risking unintended changes. To enforce idempotency, authors can use parameters like creates or removes to conditionally run tasks. More robustly, they can register command output and use changed when or when clauses to control execution based on actual system conditions. This discipline ensures predictable and resilient automation


How do Ansible roles promote modularity and collaboration in automation workflows? Describe the purpose of each key file in a standard role directory.

Ansible roles organize automation into reusable, modular units, making playbooks cleaner and easier to share.

  • tasks/main.yml: contains the core tasks the role performs.
  • handlers/main.yml: defines actions triggered by task notifications.
  • defaults/main.yml: sets low-priority, user-overridable variables.
  • vars/main.yml: holds high-priority internal variables.
  • meta/main.yml: includes role metadata and dependencies.

You’re tasked with deploying a new version of a multi-tier web application (web frontends, APIs, database) behind a load balancer. How would you design an Ansible-based rolling update strategy to ensure zero downtime? Describe the key plays, tasks, and features you'd use.

To ensure zero downtime during a rolling update of a multi-tier web application, Design a master orchestration playbook that sequences the deployment across tiers starting with database migrations, followed by API services, and finally the web frontends.

For the web and API tiers, Iuse the serial keyword (e.g., serial: 1 or serial: 25%) to update servers in controlled batches. Before updating each server, use the ansible.builtin.uri module to call the load balancer’s API and drain or disable the server from the active pool. Once isolated, run the application deployment role.

After deployment, Iperform health checks using either ansible.builtin.uri to hit a health endpoint or ansible.builtin.wait_for to confirm the service port is listening. If the server passes, re-enable it in the load balancer and proceed to the next one.

To handle failures gracefully, wrap the critical steps in a block with a rescue section. If anything fails like a health check. I could trigger a rollback, alert an operator, or re-add the server to the load balancer in its previous state to maintain capacity.

This strategy ensures safe, staged updates with minimal disruption to live traffic.


Question : What is azure pipline
An Azure Pipeline is a cloud-based service within the Azure DevOps ecosystem that automatically builds, tests, and deploys your code using continuous integration (CI) and continuous delivery (CD). It works across any programming language, platform, or cloud target. 
Core Structural Hierarchy
  • Trigger: The event that tells the pipeline to run, such as pushing code to a branch or making a pull request.
  • Stage: A major boundary in the pipeline (e.g., "Build Code", "Run QA Tests", "Deploy to Production").
  • Job: A series of steps that runs on a single execution agent. Jobs can run sequentially or in parallel.
  • Step/Task: The smallest building block, such as a script, command, or pre-built plugin that compiles code or copies files.
  • Agent: The computing engine (hosted by Microsoft or managed by you) that executes the jobs.
  • Artifact: The physical output generated by a build step (like a .zip or .war file) used for deployment. [
Standard Configuration Methods
You can configure pipelines using two primary models: 
  1. YAML Pipelines (Recommended): Your pipeline is defined entirely as code inside a file named azure-pipelines.yml at the root of your repository. This allows you to track pipeline changes using version control. 
  2. Classic Editor: A visual, drag-and-drop user interface inside the Azure DevOps web portal. This option is generally used for simpler legacy systems or quick graphical proofs-of-concept. 
Basic Starter YAML Template
This simple configuration executes every time code updates on the main branch, running on a Microsoft-hosted Ubuntu environment: 
yaml
trigger:
- main

pool:
  vmImage: ubuntu-latest

stages:
- stage: BuildStage
  jobs:
  - job: BuildJob
    steps:
    - script: echo "Compiling application source code..."
      displayName: 'Compile Code'

- stage: DeployStage
  dependsOn: BuildStage
  jobs:
  - job: DeployJob
    steps:
    - script: echo "Deploying artifact to hosting environment..."
      displayName: 'Execute Deployment'
Steps to Create a Pipeline
  1. Log into your organization via the Azure DevOps Portal.
  2. Select your target project, choose Pipelines from the left panel, and click New Pipeline.
  3. Point the wizard to your code repository (e.g., Azure Repos, GitHub, or Bitbucket).
  4. Select a preset configuration template matching your technology stack (such as Node.js, .NET Core, or Maven).
  5. Review the generated YAML schema, click Save and Run, and monitor the real-time build logs. [

Question : how to use ansible.builtin.import_task

ansible.builtin.import_tasks is a static reuse module in Ansible. It injects a list of external tasks into a playbook at parse time (before execution begins). Conditional statements or tags applied to an import_tasks line copy down to every individual child task inside the imported file. 
Practical Example
Main Playbook (playbook.yml):
yaml
- hosts: all
  tasks:
    - name: Import web server configuration tasks
      ansible.builtin.import_tasks: web_tasks.yml
      tags: ['web']
Task File (web_tasks.yml):
yaml
- name: Install Nginx
  ansible.builtin.apt:
    name: nginx
    state: present

- name: Start Nginx service
  ansible.builtin.service:
    name: nginx
    state: started
Test Case
Verify parse-time loading and correct execution using ansible-playbook with a syntax check and dry run: 
bash
# Check playbook syntax and verify static file resolution
ansible-playbook --syntax-check playbook.yml

# Run a dry-run check
ansible-playbook playbook.yml --check
Expected Behavior: Ansible reads web_tasks.yml during the initial parsing phase. If web_tasks.yml is missing, the command fails immediately even before connecting to any target hosts. 
Common Troubleshooting Steps
  • Missing File Errors (ERROR! the file/tasks file could not be found):
    • Cause: import_tasks evaluates paths at parse time. The target file must physically exist on the controller.
    • Fix: Ensure the relative path points accurately to the file location from the playbook root. 
  • Using Loops (with_* or loop) Fails:
    • Cause: Loops are not supported directly on import_tasks.
    • Fix: Switch the module to ansible.builtin.include_tasks if you require runtime iteration loops. 
  • Dynamic Variable in File Path Fails:
    • Cause: Host-level inventory variables are not resolved during the parse phase for file names.
    • Fix: Pass variables via --extra-vars or use include_tasks instead for dynamic filenames. 


Question : How to used failed when 

The failed_when conditional in Ansible overrides the default failure criteria of a task, allowing you to define exactly what constitutes a failure based on command output, return codes, or variable values. 
Basic Syntax and Example
By default, Ansible marks a task as "failed" if the return code (rc) is not 0. failed_when lets you change this logic. 
Here is an example that triggers a failure if the word "Error" appears in the command output, even if the return code is 0
yaml
- name: Run custom disk check script
  ansible.builtin.command: /usr/local/bin/check_disk.sh
  register: disk_result
  failed_when: "'Error' in disk_result.stdout"
Complete Test Case Playbook
This standalone playbook demonstrates multiple conditions. It fails only if the return code is greater than 2 and the output contains the word critical.
yaml
---
- name: Test Case for failed_when
  hosts: localhost
  gather_facts: false
  tasks:

    - name: Simulate a tool execution
      ansible.builtin.shell: |
        echo "Status: critical failure detected"
        exit 3
      register: tool_output
      ignore_errors: true # Prevents the playbook from stopping completely so we can see the result

    - name: Evaluate custom failure conditions
      ansible.builtin.debug:
        msg: "The previous task met custom failure criteria!"
      failed_when: 
        - tool_output.rc > 2
        - "'critical' in tool_output.stdout"
Common Troubleshooting Scenarios
1. Variable is Undefined
  • Issue: The task crashes with an "error": "The task includes an option with an undefined variable" message.
  • Cause: You tried to inspect stdout or rc on a task that skipped or did not register output.
  • Fix: Add a check to ensure the variable exists first.
    yaml
    failed_when: disk_result.stdout is defined and "Error" in disk_result.stdout
    

2. Logical Operator Confusion (and vs or)
  • Issue: The task fails when it should pass, or passes when it should fail.
  • Cause: Listing conditions as a YAML array implies an AND operation.
  • Fix: For an OR operation, write the condition explicitly on a single line.
    yaml
    # Fails if rc is 2 OR if stdout contains 'Failed'
    failed_when: tool_output.rc == 2 or "Failed" in tool_output.stdout
    

3. Overriding changed Status
  • Issue: The task reports failed but still shows a status of changed.
  • Fix: Combine failed_when with changed_when to cleanly manage the task lifecycle state. 


Question : what is purpose of ignore_unreachable: true 

ignore_unreachable: true is an Ansible keyword that prevents a playbook from failing entirely when a managed host cannot be reached via SSH or WinRM
By default, an unreachable host is immediately dropped from the play, and any remaining tasks for that host are skipped. Enabling this keyword allows Ansible to log the failure but continue executing the playbook for other tasks or handlers, which is highly useful for multi-tier deployments or dynamic environments. 

Basic Example
You can apply ignore_unreachable at the play level or individual task level. 
yaml
---
- name: Demonstrate ignore_unreachable at task level
  hosts: all
  gather_facts: no
  tasks:
    - name: Attempt to connect to a potentially offline server
      ansible.builtin.ping:
      ignore_unreachable: true
      register: ping_result

    - name: This task runs even if the host was unreachable above
      ansible.builtin.debug:
        msg: "The ping task completed. Unreachable status: {{ ping_result.unreachable | default(false) }}"
Step-by-Step Test Case
To safely test this behavior without breaking production systems, follow this localized test scenario.
1. Setup an Inventory 
Create an inventory file named hosts.ini containing one real local host and one fake, unreachable IP address. 
ini
[servers]
localhost ansible_connection=local
fake_server ansible_host=192.0.2.1 ansible_connection=ssh
2. Create the Test Playbook 
Save the following playbook as test_unreachable.yml. It uses ignore_unreachable: true to prevent the fake_server failure from halting the execution setup.
yaml
---
- name: Test Case for ignore_unreachable
  hosts: servers
  gather_facts: no
  tasks:
    - name: Execute a command on all hosts
      ansible.builtin.command: echo "Checking connectivity"
      ignore_unreachable: true
      register: task_output

    - name: Inspect the output variables
      ansible.builtin.debug:
        msg: "Host {{ inventory_hostname }} finished with unreachable status: {{ task_output.unreachable | default(false) }}"
3. Run and Analyze Results
Execute the playbook with the inventory file: 
bash
ansible-playbook -i hosts.ini test_unreachable.yml
  • Expected CLI Output:
    Ansible will display a red UNREACHABLE! warning message for fake_server, but instead of halting, it will smoothly proceed to the "Inspect the output variables" task.
     
  • Variable State:
    For fake_server, the task_output variable will contain "unreachable": true and "failed": true. You can use this registered dictionary downstream with when: task_output.unreachable to conditionally trigger fallback tasks.

Troubleshooting Common Gotchas
  • Subsequent Tasks Fail: If a host is truly offline, setting ignore_unreachable: true on Task A means Task B will still attempt to run on that offline host. Task B will then fail with an "Unreachable" error unless you also add the keyword to Task B or add a conditional check like when: task_output.unreachable is not defined. 
  • Play-level vs Task-level: If you set ignore_unreachable: true at the play level, it applies to gather_facts. If the host is unreachable during fact gathering, Ansible ignores it and proceeds into the tasks section with an empty fact cache for that host. 
  • Handlers are Skipped: If a host becomes unreachable during a task that notified a handler, that handler will not run for the unreachable host, even if ignore_unreachable is enabled. 
  • Differentiating from ignore_errors: Do not confuse these two settings. ignore_errors: true handles cases where the host is reachable, but a command returns a non-zero exit code. ignore_errors will not catch SSH connection timeouts or connection refused errors; only ignore_unreachable can catch those. 




Question : when block details

An Ansible block groups multiple tasks together to apply shared configurations or handle errors. It functions like a try-catch-finally block in traditional programming. [
Syntax and Example
Blocks allow you to apply directives like become or when to multiple tasks at once. 
yaml
---
- name: Managed web server configuration
  hosts: webservers
  tasks:
    - name: Setup Web Server Configuration
      block:
        - name: Install Apache
          ansible.builtin.apt:
            name: apache2
            state: present

        - name: Start Apache Service
          ansible.builtin.systemd:
            name: apache2
            state: started
            enabled: true
      become: true
      when: ansible_os_family == "Debian"
Error Handling (Test Case)
Combine block, rescue, and always to handle task failures gracefully. 
  • block: Runs the main tasks.
  • rescue: Runs only if a task in the block fails.
  • always: Runs no matter what happens in the previous sections. 
yaml
---
- name: Test error handling with blocks
  hosts: localhost
  gather_facts: false
  tasks:
    - name: Attempt dangerous file operation
      block:
        - name: Read a non-existent file
          ansible.builtin.command: cat /tmp/missing_file.txt
          register: file_output

      rescue:
        - name: Handle the failure
          ansible.builtin.debug:
            msg: "The file was missing! Creating a backup file now..."

        - name: Create fallback file
          ansible.builtin.file:
            path: /tmp/missing_file.txt
            state: touch

      always:
        - name: Final cleanup task
          ansible.builtin.debug:
            msg: "This task always runs, regardless of success or failure."
Troubleshooting Common Issues
  • Invalid Directives: You cannot apply loops (loop, with_items) to a block. Apply the loop to individual tasks inside the block instead.
  • Variable Scope: Variables registered inside a failed block task may be undefined in the rescue section. Use block_failed_task or check for variable existence using is defined before referencing them.
  • Playbook Failure: If a task in the rescue section fails, the entire playbook run will fail immediately. Keep rescue tasks simple and safe.
  • Task Status: If the rescue section successfully resolves the issue, the overall play status will show as ok (or changed), not failed. [






Question : How to manage Azure Repos
Azure Repos is a dedicated set of version control tools within the Microsoft Azure DevOps suite that allows development teams to manage, track, and collaborate on their codebase. It integrates seamlessly with Azure Pipelines for automated continuous integration and continuous delivery (CI/CD). 
Types of Version Control Supported
  • Git: The modern standard, offering distributed version control where every developer has a full copy of the repository locally.
  • Team Foundation Version Control (TFVC): A legacy, centralized version control system where history is maintained exclusively on a server. 
Core Features of Azure Repos
  • Unlimited Private Repos: Host unlimited repositories for small or enterprise-scale projects.
  • Pull Requests (PRs): Facilitate asynchronous code reviews, inline discussions, and feedback loops before merging code.
  • Branch Policies: Protect critical branches (like main) by enforcing rules such as required reviewers, successful build validation, or mandatory work item linking.
  • Semantic Code Search: Locate specific classes, functions, or text across all repositories using advanced query syntax.
  • IDE & Tooling Flexibility: Connect natively using Visual Studio, VS Code, Git CLI, or any standard Git client. [
Standard Git Workflow
  1. Create/Initialize: Set up a new repository in your project via the web portal or command line.
  2. Clone: Copy the remote repository locally using a secure HTTPS or SSH connection string.
  3. Branch: Create a feature branch to write your code changes safely away from production code.
  4. Commit & Push: Commit your local changes and push the branch back to Azure Repos.
  5. Merge: Open a pull request, complete code reviews, pass build pipelines, and merge changes. [

or

Azure DevOps Repos for Ansible AWX
Azure DevOps (AzDO) Repos serves as the single source of truth for your infrastructure as code (IaC). It securely stores your Ansible playbooks, inventories, and variables, tracking every change through Git version control
When integrated with Ansible AWX (the upstream open-source version of Red Hat Ansible Automation Platform), AzDO Repos acts as the remote project repository. AWX automatically pulls the latest playbooks from your AzDO Git repository to execute consistent, repeatable deployments. 

Workflow Architecture
[ Developer ] ---> ( Git Push ) ---> [ Azure DevOps Repo ]
                                              |
                                     ( Webhook Trigger )
                                              v
[ Managed Infrastructure ] <--- [ Ansible AWX Project Sync & Job Execution ]
  1. Code Commit: A developer updates an Ansible playbook or inventory file locally and pushes it to Azure Repos.
  2. Automation Trigger: Azure DevOps fires a service hook (webhook) to AWX, or AWX polls the repository on a schedule.
  3. Project Sync: AWX pulls the latest code from the specific Git branch.
  4. Job Execution: AWX runs the playbook against target environments using secure credentials stored natively within AWX. 

Step-by-Step Implementation Example
1. Repository Structure (Azure Repos)
Create a clean directory layout in your Azure DevOps Git repository: 
text
├── ansible.cfg
├── environments/
│   ├── dev/
│   │   └── hosts.yml
│   └── prod/
│       └── hosts.yml
├── playbooks/
│   └── deploy_web.yml
└── roles/
    └── webserver/
        └── tasks/
            └── main.yml
2. Sample Playbook (playbooks/deploy_web.yml)
yaml
---
- name: Configure Corporate Web Servers
  hosts: webservers
  become: yes
  tasks:
    - name: Ensure Apache is at the latest version
      ansible.builtin.package:
        name: httpd
        state: latest

    - name: Start and enable Apache service
      ansible.builtin.service:
        name: httpd
        state: started
        enabled: yes
3. Connecting Azure Repos to Ansible AWX
  • Generate Git Credentials: In Azure DevOps, go to User Settings > Personal Access Tokens (PAT). Create a token with Code (Read) permissions. 
  • Configure AWX Credentials:
    • Log into AWX and navigate to Credentials > Add.
    • Set Credential Type to Source Control.
    • Input your Azure DevOps username and paste the PAT into the Password/Token field. 
  • Create AWX Project:
    • Navigate to Projects > Add.
    • Set Source Control Type to Git.
    • Paste your Azure Repos HTTPS clone URL into the Source Control URL field.
    • Select the Source Control credential you created above.
    • Enable Update Revision on Launch to ensure AWX always pulls the newest code before running. 

Testing and Validation Case
To ensure your code updates do not break your production environments, implement an automated CI/CD validation pipeline inside Azure DevOps using an azure-pipelines.yml file. [
Automated Test Case (azure-pipelines.yml
This configuration tests your Ansible playbooks for syntax errors and style violations automatically on every pull request.
yaml
trigger:
  - main

pr:
  - main

pool:
  vmImage: 'ubuntu-latest'

steps:
- task: UsePythonVersion@0
  inputs:
    versionSpec: '3.10'
  displayName: 'Set up Python'

- script: |
    python -m pip install --upgrade pip
    pip install ansible ansible-lint
  displayName: 'Install Ansible and Linting Tools'

- script: |
    ansible-lint playbooks/deploy_web.yml
  displayName: 'Run Ansible Lint (Static Code Analysis)'

- script: |
    ansible-playbook --syntax-check playbooks/deploy_web.yml
  displayName: 'Run Playbook Syntax Check'

or
Azure Repos is crucial for managing Ansible AWX and workflows. It acts as the single source of truth for playbooks, roles, and inventory files. Developers edit files in Visual Studio Code (VS Code), commit changes to Azure Repos, and trigger AWX projects to sync and execute automation safely
Workflow and Example
A standard Git workflow connects Visual Studio Code, Azure Repos, and Ansible AWX:
  • Write Code in VS Code: Clone your Azure repo locally. Create a feature branch. Write your Ansible playbook (site.yaml) and inventory files.
  • Commit and Push: Stage and commit your changes in VS Code. Push the feature branch to Azure Repos.
  • Pull Request (PR): Create a PR in Azure DevOps to merge the feature branch into the main branch. Peer review the YAML syntax.
  • AWX Sync: Configure Ansible AWX with a project pointing to your Azure Git repository via a Personal Access Token (PAT). AWX pulls the updated main branch automatically or via webhook.
  • Run Job Template: Execute the job template in AWX using the synced playbook from Azure Repos. [
Example Playbook & Test Case
Example Ansible Playbook (site.yaml)
yaml
---
- hosts: webservers
  become: yes
  tasks:
    - name: Ensure Nginx is installed
      apt:
        name: nginx
        state: present
    - name: Ensure Nginx is running
      service:
        name: nginx
        state: started
Test Case / Validation Scenario
  • Syntax Test (Pre-commit): Run ansible-playbook --syntax-check site.yaml locally inside VS Code terminal to verify YAML indentation and syntax rules.
  • Integration Test: Trigger an AWX job template in "Check Mode" (dry run) against a staging environment to confirm task viability before applying production changes. 
Interview Questions and Answers
  • Q: How does Ansible AWX authenticate with a private Azure DevOps Git repository?
    A: AWX authenticates using a Git Source Control credential configured with a Personal Access Token (PAT) generated from Azure DevOps.
     
  • Q: Why use VS Code for Ansible development instead of editing directly in AWX?
    A: VS Code provides local extension linting, syntax validation (ansible-lint), and local Git staging control before changes affect production workflows.
     
  • Q: How do you automate AWX project updates when a change is merged into Azure Repos?
    A: You can set the AWX Job Template to update the project on launch, or configure an Azure DevOps Service Hook / Webhook to call the AWX API whenever a push or merge occurs on the main branch.
     

Question : How to integrate Ansible AWX with Azure DevOps (ADO)

To integrate Ansible AWX with Azure DevOps (ADO), you need to sync your Ansible playbooks from Azure Repos to AWX and trigger AWX job templates from Azure Pipelines
Here is the complete, step-by-step implementation guide.
1. Sync Azure Repos to Ansible AWX (SCM Setup)
AWX uses Git to pull playbooks. Because standard HTTPS git authentication can struggle with Azure DevOps authentication requirements, the most reliable method is using SSH keys
In Azure DevOps:
  1. Generate an SSH key pair locally (ssh-keygen -t rsa -b 4048).
  2. Log into Azure DevOps.
  3. Click your User Profile Icon (top right) → User settingsSSH public keys.
  4. Click + New Key, paste your public key (id_rsa.pub), and save.
  5. Go to your repository and copy the SSH clone URL (e.g., git@://azure.com:v3/...). [
In Ansible AWX:
  1. Navigate to CredentialsAdd.
  2. Name it Azure DevOps SSH Key.
  3. Set Credential Type to Source Control.
  4. Paste your private key (id_rsa) into the SSH Private Key box. Save it.
  5. Navigate to ProjectsAdd.
  6. Set Source Control Type to Git.
  7. Paste your Azure DevOps SSH clone URL into the Source Control URL field.
  8. Select the Azure DevOps SSH Key credential you created. Save and click Sync. [

2. Configure the AWX Job Template
Before automation can happen, AWX needs a template to execute. 
  1. Navigate to TemplatesAddAdd job template.
  2. Link your Inventory, the newly synced Project, and select your target Playbook.
  3. Under Variables, check the box Prompt on Launch for Extra Variables (this allows Azure DevOps to pass runtime parameters dynamically).
  4. Save the template. Note the ID number from the URL (e.g., /templates/job_template/42/). [

3. Generate an AWX API Token
Azure DevOps needs a token to securely talk to the AWX REST API. 
  1. In AWX, click on Users and select your automation user.
  2. Click the Tokens tab → Add.
  3. Set Scope to Write and save.
  4. Copy the generated Bearer Token immediately. 

4. Create the Azure DevOps Pipeline
You will use a bash script step inside your azure-pipelines.yml file to send an API request to AWX. This triggers the template automatically when changes occur. 
Pipeline Configuration (azure-pipelines.yml)
yaml
trigger:
  - main

pool:
  vmImage: 'ubuntu-latest'

variables:
  # Map your secret token securely in the ADO library pipeline UI
  AWX_TOKEN: $(AWX_API_TOKEN) 
  AWX_URL: 'https://your-awx-url.com'
  TEMPLATE_ID: '42' # Replace with your template ID

steps:
- bash: |
    echo "Triggering Ansible AWX Job Template..."
    
    # Send the API request to launch the job
    RESPONSE=$(curl -X POST \
      -H "Authorization: Bearer $(AWX_TOKEN)" \
      -H "Content-Type: application/json" \
      -d '{"extra_vars": {"build_id": "$(Build.BuildId)", "environment": "production"}}' \
      -s -k "$(AWX_URL)/api/v2/job_templates/$(TEMPLATE_ID)/launch/")
    
    # Extract Job ID to track execution status
    JOB_ID=$(echo $RESPONSE | grep -oP '"job":\s*\K[0-9]+')
    
    if [ -z "$JOB_ID" ]; then
      echo "Failed to initiate AWX Job."
      echo "Response: $RESPONSE"
      exit 1
    fi
    
    echo "AWX Job successfully launched. Job ID: $JOB_ID"
    
    # Optional: Poll AWX API to track completion status
    echo "Checking job status..."
    while true; do
      STATUS_RESP=$(curl -X GET -H "Authorization: Bearer $(AWX_TOKEN)" -s -k "$(AWX_URL)/api/v2/jobs/$JOB_ID/")
      STATUS=$(echo $STATUS_RESP | grep -oP '"status":\s*"\K[^"]+')
      
      echo "Current Status: $STATUS"
      
      if [ "$STATUS" == "successful" ]; then
        echo "Ansible Playbook completed successfully!"
        break
      elif [ "$STATUS" == "failed" ] || [ "$STATUS" == "error" ] || [ "$STATUS" == "canceled" ]; then
        echo "Ansible Playbook failed."
        exit 1
      fi
      sleep 10
    done
  displayName: 'Trigger and Monitor Ansible AWX Job'
5. Securely Store Variables in Azure DevOps
To prevent plain-text exposure of your AWX token in your repository:
  1. Open your pipeline in the Azure DevOps editor.
  2. Click Variables in the top right corner.
  3. Click New variable.
  4. Name it AWX_API_TOKEN.
  5. Paste your AWX token into the value box.
  6. Check Keep this value secret to mask it in logs. 
When your code changes are pushed to the main branch, the pipeline will auto-fire, send the build details to AWX as extra_vars, and watch the deployment succeed in real-time. 


Question : How to set up code deployments in Azure DevOps,


How to Run Ansible Playbooks From AWX GUI | Step-by-Step Tutorial

To set up code deployments in Azure DevOps, you must manually create an Azure DevOps organization via the web portal, as automated organization creation is not natively supported. This setup creates the foundational container for your deployment projects, pipelines, and target environments. [
 Step 1: Create an Azure DevOps Organization
  1. Navigate to Azure DevOps Services and click Start free.
  2. Sign in using your Microsoft account, GitHub account, or a Work/School account linked to Microsoft Entra ID. [
  3. Click New organization from the left pane or click Continue on the initial prompt. 
  4. Enter an Organization Name following these constraints:
    • Use English alphabet letters, numbers, or hyphens only.
    • Must start and end with a letter or number.
    • Keep the name under 50 characters. 
  5. Select your closest hosting geography (e.g., United States, Europe, India) to reduce pipeline latency. 
  6. Complete the CAPTCHA and click Continue. 
 Step 2: Establish Your Deployment Project
Once inside your new organization dashboard, configure a project container to host your code repositories and pipeline triggers: [1]
  1. Click the New project button in the upper-right corner.
  2. Assign a specific Project Name and short description.
  3. Choose your visibility level (Public or Private).
  4. Select your preferred Version Control system (usually Git) and Work item process template (e.g., Agile, Scrum).
  5. Click Create. [
 Step 3: Setup the Deployment Infrastructure
After your organization and project are live, map your target servers for deployments through the Azure Pipelines tab: 
  • For Cloud App Services / Kubernetes: Go to Pipelines > Environments > Create environment to group physical or virtual cloud resources for pipeline orchestration. 
  • For On-Premises VMs: Go to Pipelines > Deployment groups > New, select your OS target type, and execute the provided registration script on your target servers. 

Question : How to manager WSL
To manage and maintain Windows Subsystem for Linux (WSL), use the wsl command-line utility in Windows PowerShell or Command Prompt. The core shutdown command is wsl --shutdown, while maintenance tasks use options like --terminate, --export, and --set-version
Shutdown Commands
  • Shut down all running distributions and the WSL 2 lightweight utility VM: wsl --shutdown
  • Stop a single specific Linux distribution: wsl --terminate <DistributionName> (or wsl -t <DistributionName>) 
Maintenance & Management Commands
  • List all installed distributions and check if they are running or stopped: wsl --list --verbose (or wsl -l -v)
  • Change a distribution version between WSL 1 and WSL 2: wsl --set-version <DistributionName> <Version>
  • Backup or export a distribution to a tar file for maintenance: wsl --export <DistributionName> <FileName.tar>
  • Restore or import a distribution from a tar backup file: wsl --import <DistributionName> <InstallLocation> <FileName.tar>
  • Completely remove and delete a distribution and its data: wsl --unregister <DistributionName> 


 To install Docker Engine on Ubuntu, the recommended approach is to set up Docker's official repository and install the native packages. This ensures you get the latest stable version and security updates. 

1. Clear Old Versions
Remove conflicting or older versions before starting: 
bash
sudo apt-get remove docker docker-engine docker.io containerd runc
Use code with caution.
2. Set Up the Repository
Install required tools and add Docker's official GPG key to verify packages: 
bash
# Update package index
sudo apt-get update

# Install prerequisites
sudo apt-get install ca-certificates curl gnupg -y

# Add the official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to APT sources
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Use code with caution.
3. Install Docker Engine
Update the repository indexes and install Docker alongside Docker Compose
bash
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y