diff --git a/.gitignore b/.gitignore index 0696b3e..8aa2026 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.terraform \ No newline at end of file +.terraform +.DS_Store diff --git a/ansible/Dockerfile b/ansible/Dockerfile index 617100c..7582a94 100644 --- a/ansible/Dockerfile +++ b/ansible/Dockerfile @@ -1,7 +1,12 @@ # docker build -f ansible/Dockerfile -t arcodange-ansible:0.0.0 ansible/ FROM python:slim -RUN apt update && apt install openssh-client socat gosu git -y +RUN apt update && apt install openssh-client socat gosu git curl -y + +RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" ; \ + chmod +x kubectl; \ + mv kubectl /usr/local/bin/; \ + curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash COPY nonroot_ssh_proxy_setup.sh /usr/local/bin/nonroot_ssh_proxy_setup.sh COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh diff --git a/ansible/README.md b/ansible/README.md index 73d1ec5..cc4ca0d 100644 --- a/ansible/README.md +++ b/ansible/README.md @@ -18,9 +18,11 @@ git clone -q --depth 1 --branch master https://github.com/arcodange/ssh-agent.gi # (cd ansible; docker build -t arcodange-ansible:0.0.0 .) docker run -d --name=ssh-agent docker-ssh-agent:latest docker run --rm --volumes-from=ssh-agent -v ~/.ssh:/.ssh -it docker-ssh-agent:latest ssh-add /root/.ssh/id_rsa -docker run --rm -u root --name test --volumes-from=ssh-agent -v $PWD:/home/arcodange/code arcodange-ansible:0.0.0 \ -# -e ANSIBLE_VAULT_PASSWORD_FILE=$ANSIBLE_VAULT_PASSWORD_FILE -v $ANSIBLE_VAULT_PASSWORD_FILE:$ANSIBLE_VAULT_PASSWORD_FILE \ before the arcodange-ansible image name -ansible-playbook ansible/arcodange/factory/playbooks/setup/03cicd.yml -i ansible/arcodange/factory/inventory -vv +docker run --rm -u root --name test --volumes-from=ssh-agent -v $PWD:/home/arcodange/code \ +-v "$HOME"/.kube/config:/home/arcodange/.kube/config \ +-e ANSIBLE_VAULT_PASSWORD_FILE=$ANSIBLE_VAULT_PASSWORD_FILE -v $ANSIBLE_VAULT_PASSWORD_FILE:$ANSIBLE_VAULT_PASSWORD_FILE \ +arcodange-ansible:0.0.0 \ +ansible-playbook ansible/arcodange/factory/playbooks/03_cicd.yml -i ansible/arcodange/factory/inventory -vv ``` ### use vault with single password @@ -36,7 +38,7 @@ ansible-playbook ansible/arcodange/factory/playbooks/setup/03cicd.yml -i ansible ANSIBLE_VAULT_PASSWORD_FILE=~/.local/bin/read-vault-key.sh; mkdir -p `dirname $ANSIBLE_VAULT_PASSWORD_FILE`; set +o histexpand; echo -e "#!/bin/bash\nkubectl get secret -n kube-system arcodange-ansible-vault --template='{{index .data.pass | base64decode}}'" > $ANSIBLE_VAULT_PASSWORD_FILE; -set -o histexpand; chmod +x $ANSIBLE_VAULT_PASSWORD_FILE; echo 'export ANSIBLE_VAULT_PASSWORD_FILE=$ANSIBLE_VAULT_PASSWORD_FILE' >> `find ~ -maxdepth 1 -type f -name '\.*profile' -or -name '\.bashrc' | head -n1` +set -o histexpand; chmod +x $ANSIBLE_VAULT_PASSWORD_FILE; echo "export ANSIBLE_VAULT_PASSWORD_FILE=$ANSIBLE_VAULT_PASSWORD_FILE" >> `find ~ -maxdepth 1 -type f -name '\.*profile' -or -name '\.bashrc' | head -n1` ``` ### a tool to reuse a ssh agent (not required) diff --git a/ansible/arcodange/factory/img/arcodange-org.jpeg b/ansible/arcodange/factory/img/arcodange-org.jpeg new file mode 100644 index 0000000..c1ab1ce Binary files /dev/null and b/ansible/arcodange/factory/img/arcodange-org.jpeg differ diff --git a/ansible/arcodange/factory/img/arcodange.jpeg b/ansible/arcodange/factory/img/arcodange.jpeg new file mode 100644 index 0000000..6356091 Binary files /dev/null and b/ansible/arcodange/factory/img/arcodange.jpeg differ diff --git a/ansible/arcodange/factory/inventory/group_vars/hard_disk/gitea_vault.yml b/ansible/arcodange/factory/inventory/group_vars/hard_disk/gitea_vault.yml index ba7e292..f9dc697 100644 --- a/ansible/arcodange/factory/inventory/group_vars/hard_disk/gitea_vault.yml +++ b/ansible/arcodange/factory/inventory/group_vars/hard_disk/gitea_vault.yml @@ -1,8 +1,13 @@ $ANSIBLE_VAULT;1.1;AES256 -33313163383239336537323061393666626430633263316637393032346464636561616166633332 -3861353632626535336234643561356434653036663165300a363138343731643235666562303564 -31633264633966666333656162313533396431396664336232646165626131396665303233393638 -3261636464326534630a666332636135643230343636383139306436616238623536373764333434 -38363666363039303633353365356236393462393166313539353333386465363163666134393638 -35613239653231333639343363303938373139373638663462633864656339336366623862613736 -313839346363623535313733613736663462 +66376231363631663639623736353861383337333863623761303438643831653061373338306366 +3762316261326433316166393132663034373636313935660a353962653931643131306134663264 +64636264393338366363333932366163393036326362353630656132326534663239306639336531 +3239373433386332640a653262633333653037646236366362333838356534623935613534376465 +66633335636235323035656332356566343738363661363066653239653037643539323533643534 +38376465663637646637326436306631663135333361666635303936643562356365616164636565 +39313231623630386332363262376364383935353534663465333362356631383334396366643463 +65616130613936343035643736623137313665373462353531326365396638633165326139343233 +31313933313161343265373865643638616134303834396563623366633136616333613433323035 +32643336343438646361616364336466366165363464323466363034373531323839363863396236 +34343731386364613739666461633564646135306231366135396562383565383562396639316164 +33626266643765653765 diff --git a/ansible/arcodange/factory/inventory/hosts.yml b/ansible/arcodange/factory/inventory/hosts.yml index 4ad20e9..7598e2a 100644 --- a/ansible/arcodange/factory/inventory/hosts.yml +++ b/ansible/arcodange/factory/inventory/hosts.yml @@ -2,8 +2,10 @@ raspberries: hosts: pi1: ansible_host: pi1.home # setup http://192.168.1.1/ Réseau/DNS + ansible_ssh_extra_args: '-o StrictHostKeyChecking=no' pi2: ansible_host: pi2.home + ansible_ssh_extra_args: '-o StrictHostKeyChecking=no' internetPi1: ansible_host: arcodange.duckdns.org diff --git a/ansible/arcodange/factory/playbooks/03_cicd.yml b/ansible/arcodange/factory/playbooks/03_cicd.yml index 10c0fb0..544cded 100644 --- a/ansible/arcodange/factory/playbooks/03_cicd.yml +++ b/ansible/arcodange/factory/playbooks/03_cicd.yml @@ -137,4 +137,13 @@ project_src: "/home/pi/arcodange/docker_composes/arcodange_factory_gitea_action" pull: missing state: present - register: deploy_result \ No newline at end of file + register: deploy_result + + - name: Deploy Argo CD + run_once: true + block: + - name: Set factory repo + include_role: + name: arcodange.factory.gitea_repo + vars: + gitea_repo_name: factory \ No newline at end of file diff --git a/ansible/arcodange/factory/playbooks/setup/gitea.yml b/ansible/arcodange/factory/playbooks/setup/gitea.yml index 8cda1c4..cdfa76a 100644 --- a/ansible/arcodange/factory/playbooks/setup/gitea.yml +++ b/ansible/arcodange/factory/playbooks/setup/gitea.yml @@ -1,8 +1,9 @@ --- - name: Setup Gitea - hosts: hard_disk + hosts: gitea:&hard_disk gather_facts: yes become: false + run_once: true vars: applications: "{{ hard_disk__applications }}" @@ -37,4 +38,117 @@ postgres_user: |- {{ applications.gitea.dockercompose.services.gitea.environment.GITEA__database__USER }} postgres_password: |- - {{ applications.gitea.dockercompose.services.gitea.environment.GITEA__database__PASSWD }} \ No newline at end of file + {{ applications.gitea.dockercompose.services.gitea.environment.GITEA__database__PASSWD }} + + - name: Create admin user + block: + - name: Use default user identity + when: gitea_user is undefined or gitea_user.name is undefined or gitea_user.email is undefined + ansible.builtin.set_fact: + gitea_base_url: http://{{ inventory_hostname }}:3000 + gitea_user: + name: arcodange + email: arcodange@gmail.com + avatar_img_path: '{{ inventory_dir }}/../img/arcodange.jpeg' + + - name: List admin users + ansible.builtin.shell: + cmd: >- + docker exec -u git {{ applications.gitea.dockercompose.services.gitea.container_name }} + gitea admin user list --admin + | awk '{print $2}' + | tail -n +2 + # tail -n +2 skips the 2-1 ("N-1" with N=2) first lines (so the first line returned by the command) + register: + gitea_admin_users_list_cmd + + - name: Create admin user + when: gitea_user.name not in gitea_admin_users_list_cmd.stdout.split() + ansible.builtin.command: >- + docker exec -u git {{ applications.gitea.dockercompose.services.gitea.container_name }} + gitea admin user create + --username {{ gitea_user.name }} + --email {{ gitea_user.name }} + --random-password + + - name: Generate Gitea Token + include_role: + name: arcodange.factory.gitea_token + + - name: Lecture bases64 de l'avatar de l'admin + local_action: + module: slurp + path: '{{ gitea_user.avatar_img_path | realpath }}' + register: + gitea_user_avatar_img + + - name: Upload l'avatar de l'admin + uri: + url: "{{ gitea_base_url }}/api/v1/user/avatar" + method: POST + headers: + Content-Type: application/json + Accept: application/json + Authorization: "token {{ gitea_api_token }}" + body_format: json + body: + image: "{{ gitea_user_avatar_img['content'] }}" + status_code: 204 + + - set_fact: + gitea_org_name: arcodange-org + gitea_org_full_name: Arcodange + gitea_org_description: '🏹💻🪽' + gitea_org_website: https://www.arcodange.duckdns.org + gitea_org_location: Paris + gitea_org_avatar_img_path: '{{ inventory_dir }}/../img/arcodange-org.jpeg' + + - name: Vérifier si l'organisation existe dans Gitea + uri: + url: "{{ gitea_base_url }}/api/v1/orgs/{{ gitea_org_name }}" + method: GET + headers: + Authorization: "token {{ gitea_api_token }}" + status_code: 200 + register: gitea_org_check + ignore_errors: yes + + - when: gitea_org_check.status != 200 + block: + - name: Créer l'organisation dans Gitea quand elle n'existe pas + uri: + url: "{{ gitea_base_url }}/api/v1/orgs" + method: POST + headers: + Content-Type: application/json + Accept: application/json + Authorization: "token {{ gitea_api_token }}" + body_format: json + body: + username: "{{ gitea_org_name }}" + full_name: "{{ gitea_org_full_name }}" + description: "{{ gitea_org_description }}" + visibility: private + website: "{{ gitea_org_website }}" + location: "{{ gitea_org_location }}" + status_code: 201 + + - name: Lecture bases64 de l'avatar de l'organization + local_action: + module: slurp + path: '{{ gitea_org_avatar_img_path | realpath }}' + register: + gitea_org_avatar_img + + - name: Upload l'avatar de l'organization + uri: + url: "{{ gitea_base_url }}/api/v1/orgs/{{ gitea_org_name }}/avatar" + method: POST + headers: + Content-Type: application/json + Accept: application/json + Authorization: "token {{ gitea_api_token }}" + body_format: json + body: + image: "{{ gitea_org_avatar_img['content'] }}" + status_code: 204 \ No newline at end of file diff --git a/ansible/arcodange/factory/playbooks/setup/roles/deploy_gitea/defaults/main.yml b/ansible/arcodange/factory/playbooks/setup/roles/deploy_gitea/defaults/main.yml index 410f3fd..5c43ee8 100644 --- a/ansible/arcodange/factory/playbooks/setup/roles/deploy_gitea/defaults/main.yml +++ b/ansible/arcodange/factory/playbooks/setup/roles/deploy_gitea/defaults/main.yml @@ -5,3 +5,6 @@ app_name: gitea partition: gitea_data config_path: /arcodange/{{ partition }}/{{ app_name }}/config data_path: /arcodange/{{ partition }}/{{ app_name }}/data +gitea_user: + name: arcodange + email: arcodange@gmail.com \ No newline at end of file diff --git a/ansible/arcodange/factory/roles/gitea_repo/defaults/main.yml b/ansible/arcodange/factory/roles/gitea_repo/defaults/main.yml new file mode 100644 index 0000000..92f71ac --- /dev/null +++ b/ansible/arcodange/factory/roles/gitea_repo/defaults/main.yml @@ -0,0 +1,9 @@ +--- +# Nom du dépôt à créer +gitea_repo_name: factory + +gitea_username: arcodange +gitea_organization: arcodange-org + +# URL de base du serveur Gitea +gitea_base_url: http://{{ groups.gitea[0] }}:3000 diff --git a/ansible/arcodange/factory/roles/gitea_repo/tasks/main.yml b/ansible/arcodange/factory/roles/gitea_repo/tasks/main.yml new file mode 100644 index 0000000..d51c550 --- /dev/null +++ b/ansible/arcodange/factory/roles/gitea_repo/tasks/main.yml @@ -0,0 +1,133 @@ +- name: Generate Gitea Token + when: gitea_api_token is undefined + include_role: + name: arcodange.factory.gitea_token + +- name: Vérifier si le dépôt existe dans Gitea + uri: + url: "{{ gitea_base_url }}/api/v1/repos/{{ gitea_organization }}/{{ gitea_repo_name }}" + method: GET + headers: + Authorization: "token {{ gitea_api_token }}" + status_code: 200 + register: gitea_repo_check + ignore_errors: yes + +- name: Vérifier si le dépôt existe sur GitLab + uri: + url: "https://gitlab.com/api/v4/projects/{{ gitlab_root_group }}%2F{{ gitea_repo_name }}" + method: GET + headers: + Authorization: "Bearer {{ gitlab_api_token }}" + status_code: 200 + register: gitlab_repo_check + ignore_errors: yes + +- name: Vérifier si le dépôt existe sur GitHub + uri: + url: "https://api.github.com/repos/{{ github_organization }}/{{ gitea_repo_name }}" + method: GET + headers: + Authorization: "token {{ github_api_token }}" + status_code: 200 + register: github_repo_check + ignore_errors: yes + +- name: Importer un dépôt GitLab/GitHub vers Gitea + when: gitea_repo_check.status != 200 and (gitlab_repo_check.status == 200 or github_repo_check.status == 200) + uri: + url: "{{ gitea_base_url }}/api/v1/repos/migrate" + method: POST + headers: + Authorization: "token {{ gitea_api_token }}" + status_code: 201 + body_format: json + body: + service: "{{ (gitlab_repo_check.status == 200) | ternary('gitlab','github') }}" + # URL du dépôt GitHub/GitLab + clone_addr: >- + {{ (gitlab_repo_check.status == 200) | ternary(gitlab_mirror_url,github_mirror_url) }} + auth_username: "{{ gitea_username }}" # Nom d'utilisateur pour l'authentification si nécessaire + # token d'accès + auth_token: >- + {{ (gitlab_repo_check.status == 200) | ternary(gitlab_api_token,github_api_token) }} + repo_name: "{{ gitea_repo_name }}" # Nom du dépôt dans Gitea + repo_owner: "{{ github_organization }}" # Propriétaire du dépôt dans Gitea (utilisateur ou organisation + mirror: true # Activer le mirroring pour synchroniser les changements + register: migration_result + +- name: Vérifier l'importation du dépôt + debug: + msg: "Migration du dépôt vers Gitea réussie. ID du dépôt : {{ migration_result.json.id }}" + when: migration_result is defined and (migration_result.status|default(omit)) == 201 + +- name: Créer un dépôt sur GitLab si nécessaire + uri: + url: "https://gitlab.com/api/v4/projects" + method: POST + headers: + Authorization: "Bearer {{ gitlab_api_token }}" + body_format: json + body: + name: "{{ gitea_repo_name }}" + path: "{{ gitea_repo_name }}" + namespace_id: "{{ gitlab_namespace_id }}" # Remplacez par l'ID du groupe ou de l'utilisateur où le projet doit être créé + visibility: "{{ gitlab_repo_visibility | default('private') }}" # Définir la visibilité (private, internal, public) + description: "{{ gitea_repo_description | default('') }}" + status_code: 201 + when: gitlab_repo_check.status != 200 + +- name: Créer un dépôt sur GitHub si nécessaire + uri: + url: "https://api.github.com/orgs/{{ github_organization }}/repos" + method: POST + headers: + Authorization: "token {{ github_api_token }}" + body_format: json + body: + name: "{{ gitea_repo_name }}" + description: "{{ gitea_repo_description | default('') }}" + private: "{{ github_repo_private | default(true) }}" # Définir si le dépôt est privé ou public + status_code: 201 + when: github_repo_check.status != 200 + +- name: Vérifier l'existence des miroirs push sur GitHub et GitLab + uri: + url: "{{ gitea_base_url }}/api/v1/repos/{{ gitea_organization }}/{{ gitea_repo_name }}/push_mirrors" + method: GET + headers: + Authorization: "token {{ gitea_api_token }}" + return_content: yes + register: existing_mirrors + +- name: Ajouter un miroir push vers GitHub si nécessaire + uri: + url: "{{ gitea_base_url }}/api/v1/repos/{{ gitea_organization }}/{{ gitea_repo_name }}/push_mirrors" + method: POST + headers: + Authorization: "token {{ gitea_api_token }}" + body_format: json + body: + interval: "8h" + remote_address: "{{ github_mirror_url }}" + remote_username: "{{ gitea_username }}" + remote_password: "{{ github_api_token }}" + sync_on_commit: true + status_code: 200 + when: "github_mirror_url not in existing_mirrors.json | map(attribute='remote_address') | list" + +- name: Ajouter un miroir push vers GitLab si nécessaire + uri: + url: "{{ gitea_base_url }}/api/v1/repos/{{ gitea_organization }}/{{ gitea_repo_name }}/push_mirrors" + method: POST + headers: + Authorization: "token {{ gitea_api_token }}" + body_format: json + body: + interval: "8h" + remote_address: "{{ gitlab_mirror_url }}" + remote_username: "{{ gitea_username }}" + remote_password: "{{ gitlab_api_token }}" + sync_on_commit: true + status_code: 200 + when: "gitlab_mirror_url not in existing_mirrors.json | map(attribute='remote_address') | list" diff --git a/ansible/arcodange/factory/roles/gitea_repo/vars/main.yml b/ansible/arcodange/factory/roles/gitea_repo/vars/main.yml new file mode 100644 index 0000000..2226e28 --- /dev/null +++ b/ansible/arcodange/factory/roles/gitea_repo/vars/main.yml @@ -0,0 +1,10 @@ +github_api_token: '{{ hostvars[groups.gitea[0]].gitea_vault.github_api_token }}' +gitlab_api_token: '{{ hostvars[groups.gitea[0]].gitea_vault.gitlab_api_token }}' + +github_organization: '{{ gitea_organization }}' +gitlab_root_group: '{{ gitea_organization }}' +gitlab_namespace_id: 89826881 # https://gitlab.com/groups/arcodange-org/-/edit + +# URLs des miroirs sur GitLab et GitHub +gitlab_mirror_url: "https://gitlab.com/{{ gitlab_root_group | default(gitlab_username | default(gitea_username)) }}/{{ gitea_repo_name }}.git" +github_mirror_url: "https://github.com/{{ github_organization | default(github_username | default(gitea_username)) }}/{{ gitea_repo_name }}.git" diff --git a/ansible/arcodange/factory/roles/gitea_token/defaults/main.yml b/ansible/arcodange/factory/roles/gitea_token/defaults/main.yml new file mode 100644 index 0000000..fb05bf5 --- /dev/null +++ b/ansible/arcodange/factory/roles/gitea_token/defaults/main.yml @@ -0,0 +1,4 @@ +gitea_user_name: arcodange +gitea_container_name: gitea +gitea_token_scopes: write:admin,write:organization,write:package,write:repository,write:user +# gitea_base_url: 'http://{{ groups.gitea[0] }}:3000' \ No newline at end of file diff --git a/ansible/arcodange/factory/roles/gitea_token/tasks/main.yml b/ansible/arcodange/factory/roles/gitea_token/tasks/main.yml new file mode 100644 index 0000000..26fe56d --- /dev/null +++ b/ansible/arcodange/factory/roles/gitea_token/tasks/main.yml @@ -0,0 +1,23 @@ +# to see generated tokens +# go to https://gitea.arcodange.duckdns.org/user/settings/applications + +- when: gitea_api_token is undefined + block: + + - name: Create new token for ansible + delegate_to: "{{ groups.gitea[0] }}" + delegate_facts: true + ansible.builtin.command: >- + docker exec -u git {{ gitea_container_name }} + gitea admin user generate-access-token + --username {{ gitea_user_name }} + --token-name {{ gitea_token_name }} + --raw + --scopes {{gitea_token_scopes}} + register: gitea_api_token_cmd + vars: + # ansible_date_time requires having gathered facts + gitea_token_name: ansible-{{ ansible_date_time.iso8601 }} + + - ansible.builtin.set_fact: + gitea_api_token: '{{ gitea_api_token_cmd.stdout }}' \ No newline at end of file