Automate GitLab with Ansible - kinda
Tags: devops, tutorial, 100daysofcode, git
Published: 2020-02-10 21:02:38

So there I was, automatin' and integratin' again.  What can I say, it does get the best of me at times...

My task was to provide a way to automate the clean up of GitLab user namespaces, and import in a fresh repo from GitHub for NN student workshop users.  Doesn't sound too hard eh?

So come to find out the GitLab module in Ansible is SUPER old and not really maintained.  No problem, I'll just ping the GitHub API with Ansible.

**Why do that instead of using something like Bash to perform cURL requests?**  Because the rest of the deployment already uses Ansible and it's much easier to just toss in a few extra tasks instead of bringing along an extra script and dropping into a different execution context.

## 1. Create the main Ansible Playbook

There's two Ansible files, and you'll see why shortly.  First, let's create the `configure_users.yaml` file with the following content:

```yaml
---
- name: Configure GitLab Workshop User Instances
  hosts: localhost
  gather_facts: false
  vars:
  - student_count: 50
  - github_personal_access_token: your_github_pat
  - github_repo: kenmoini/s2f-tasks-app
  - gitlab_endpoint: https://gitlab.example.com

  tasks:

  - name: Get GitHub Repo Import Repo ID
    uri:
      url: "https://api.github.com/repos/{{ github_repo }}"
      method: GET
      validate_certs: no
      status_code:
          - 200
          - 201
          - 409
    register: github_repo_info

  - name: Configure Per User GitLab Environment
    include_tasks: actual_user_config.yaml
    with_sequence: start=0 end="{{ student_count }}"
```

1. A few variables to keep an eye on, you need to pass in your GitHub Personal Access Token in order to import the repo, as well as the actual repo.  We're also provisioning for 50 student user seats.
2. GitLab imports GitHub repos by their Repo ID, the numeric value, not the string.  So our first task is to get that Repo ID
3. Next, we loop through an external tasks file - Blocks don't support loops.

## 2. Per-seat tasks

Let's create that external `actual_user_config.yaml` file:

```yaml
---
- name: GitLab Post | Obtain Access Token
  uri:
    url: "{{ gitlab_endpoint }}/oauth/token"
    method: POST
    validate_certs: no
    status_code: 200
    body_format: json
    headers:
        Content-Type: application/json
    body: >
        {
        "grant_type": "password",
        "username": "student{{ item }}",
        "password": "user_password_here"
        }
  register: gitlab_access_token
  tags:
  - always

- name: GitLab Get | Get All User projects
  uri:
    url: "{{ gitlab_endpoint }}/api/v4/users/student{{ item }}/projects"
    method: GET
    validate_certs: no
    status_code:
        - 200
        - 201
        - 409
    headers:
        Content-Type: application/json
        Authorization: Bearer {{ gitlab_access_token.json.access_token }}
  register: user_projects
  tags:
  - destroy

- name: GitLab Post | Delete Projects via API
  uri:
    url: "{{ gitlab_endpoint }}/api/v4/projects/{{ project.id }}"
    method: DELETE
    validate_certs: no
    status_code:
        - 200
        - 201
        - 202
        - 409
    headers:
        Content-Type: application/json
        Authorization: Bearer {{ gitlab_access_token.json.access_token }}
  loop: "{{ user_projects.json }}"
  loop_control:
    loop_var: project
  tags:
  - destroy

- name: GitLab Post | Import Project from GitHub
  uri:
    url: "{{ gitlab_endpoint }}/api/v4/import/github"
    method: POST
    validate_certs: no
    status_code:
        - 200
        - 201
        - 409
        - 400
    body_format: json
    headers:
        Content-Type: application/json
        Authorization: Bearer {{ gitlab_access_token.json.access_token }}
    body: >
        {
        "personal_access_token": "{{ github_personal_access_token }}",
        "repo_id": "{{ github_repo_info.json.id }}",
        "target_namespace": "student{{ item }}"
        }
  tags:
  - import
```

1. This external set of tasks is executed top-to-bottom per-student.
2. First, we get an authentication token to use for the following tasks
3. Next, there are tagged tasks to get all the repos a user has access to
4. We can then destroy all the repos under the user
5. Once it's all cleaned up, we'll import a new repo fresh into each student namespace

## 3. Rolllll it

Now you can simply run one of the following commands:

```bash
ansible-playbook configure_users.yaml --tags destroy
# or
ansible-playbook configure_users.yaml --tags import
# OR OR
ansible-playbook configure_users.yaml --tags "destroy,import"
```

Hopefully, this helps in case you're looking to automate GitLab with Ansible.  If there's not a particular Ansible module, or if it's not up to snuff then don't be afraid to use APIs if there's one available!