From 9ca7b14364ba2a4b6712ec3364252ae7b5512cfd Mon Sep 17 00:00:00 2001 From: Jon Date: Fri, 23 Feb 2024 12:10:30 +0930 Subject: [PATCH 1/8] ci: attempt to fix multi-arch builds !9 --- .gitlab-ci.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0d759ff..2b0f213 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -146,9 +146,9 @@ Github (Push --mirror): docker buildx imagetools inspect $DOCKER_IMAGE_BUILD_REGISTRY/$DOCKER_IMAGE_BUILD_NAME:$DOCKER_IMAGE_BUILD_TAG; - DOCKER_MULTI_ARCH_IMAGES=$(docker buildx imagetools inspect "$DOCKER_IMAGE_BUILD_REGISTRY/$DOCKER_IMAGE_BUILD_NAME:$DOCKER_IMAGE_BUILD_TAG" --format "{{ range .Manifest.Manifests }}$DOCKER_IMAGE_BUILD_REGISTRY/$DOCKER_IMAGE_BUILD_NAME:$DOCKER_IMAGE_BUILD_TAG@{{ println .Digest }} {{end}}") + #DOCKER_MULTI_ARCH_IMAGES=$(docker buildx imagetools inspect "$DOCKER_IMAGE_BUILD_REGISTRY/$DOCKER_IMAGE_BUILD_NAME:$DOCKER_IMAGE_BUILD_TAG" --format "{{ range .Manifest.Manifests }}$DOCKER_IMAGE_BUILD_REGISTRY/$DOCKER_IMAGE_BUILD_NAME:$DOCKER_IMAGE_BUILD_TAG@{{ println .Digest }} {{end}}") - echo "[DEBUG] DOCKER_MULTI_ARCH_IMAGES=$DOCKER_MULTI_ARCH_IMAGES"; + # echo "[DEBUG] DOCKER_MULTI_ARCH_IMAGES=$DOCKER_MULTI_ARCH_IMAGES"; # done; @@ -177,23 +177,23 @@ Github (Push --mirror): # fi; - echo "[DEBUG] DOCKER_IMAGE_PUBLISH_NAME=$DOCKER_IMAGE_PUBLISH_NAME"; + # echo "[DEBUG] DOCKER_IMAGE_PUBLISH_NAME=$DOCKER_IMAGE_PUBLISH_NAME"; # echo "[DEBUG] final: DOCKER_HUB_TAG=$DOCKER_HUB_TAG"; - echo "[DEBUG] DOCKER_MULTI_ARCH_IMAGES=$DOCKER_MULTI_ARCH_IMAGES"; - - + # echo "[DEBUG] DOCKER_MULTI_ARCH_IMAGES=$DOCKER_MULTI_ARCH_IMAGES"; + + if [ "${CI_COMMIT_TAG}" ]; then - docker buildx imagetools create $DOCKER_MULTI_ARCH_IMAGES --tag $DOCKER_IMAGE_PUBLISH_REGISTRY/$DOCKER_IMAGE_PUBLISH_NAME:$CI_COMMIT_TAG; + docker buildx imagetools create $DOCKER_IMAGE_BUILD_REGISTRY/$DOCKER_IMAGE_BUILD_NAME:$DOCKER_IMAGE_BUILD_TAG --tag $DOCKER_IMAGE_PUBLISH_REGISTRY/$DOCKER_IMAGE_PUBLISH_NAME:$CI_COMMIT_TAG; - docker buildx imagetools create $DOCKER_MULTI_ARCH_IMAGES --tag $DOCKER_IMAGE_PUBLISH_REGISTRY/$DOCKER_IMAGE_PUBLISH_NAME:latest; + docker buildx imagetools create $DOCKER_IMAGE_BUILD_REGISTRY/$DOCKER_IMAGE_BUILD_NAME:$DOCKER_IMAGE_BUILD_TAG --tag $DOCKER_IMAGE_PUBLISH_REGISTRY/$DOCKER_IMAGE_PUBLISH_NAME:latest; else - docker buildx imagetools create $DOCKER_MULTI_ARCH_IMAGES --tag $DOCKER_IMAGE_PUBLISH_REGISTRY/$DOCKER_IMAGE_PUBLISH_NAME:dev; + docker buildx imagetools create $DOCKER_IMAGE_BUILD_REGISTRY/$DOCKER_IMAGE_BUILD_NAME:$DOCKER_IMAGE_BUILD_TAG --tag $DOCKER_IMAGE_PUBLISH_REGISTRY/$DOCKER_IMAGE_PUBLISH_NAME:dev; fi; From 49682d6038328f79d349e3d06f611dcb5e5e144c Mon Sep 17 00:00:00 2001 From: Jon Date: Fri, 23 Feb 2024 12:39:15 +0930 Subject: [PATCH 2/8] test(docker): unit test to ensure collection installed within container !9 fixes #9 --- .gitlab-ci.yml | 47 ++++++++++++++++++++++++++++++++- .gitlab/unit-test.gitlab-ci.yml | 33 +++++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 .gitlab/unit-test.gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2b0f213..fcf4110 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,6 +21,9 @@ variables: include: + + - local: .gitlab/unit-test.gitlab-ci.yml + - project: nofusscomputing/projects/gitlab-ci ref: development file: @@ -239,10 +242,31 @@ Docker Container (dev): - when: never +test:unit:docker:collection:installed:dev: + extends: .docker_collection_installed + needs: + - "Docker Container (dev)" + rules: + - if: $CI_COMMIT_TAG + when: never + + - if: "$CI_COMMIT_AUTHOR =='nfc_bot '" + when: never + + - if: + $CI_COMMIT_BRANCH != "master" + && + $CI_PIPELINE_SOURCE == "push" + when: always + + - when: never + + Docker Hub (dev): extends: .publish-docker-hub needs: - "Docker Container (dev)" + - "test:unit:docker:collection:installed:dev" resource_group: docker-build rules: - if: $CI_COMMIT_TAG @@ -255,7 +279,7 @@ Docker Hub (dev): $CI_COMMIT_BRANCH == "development" && $CI_PIPELINE_SOURCE == "push" - when: always + when: on_success - when: never @@ -281,10 +305,31 @@ Docker Container: - when: never +test:unit:docker:collection:installed: + extends: .docker_collection_installed + needs: + - Docker Container + rules: + - if: $CI_COMMIT_TAG + when: on_success + + - if: "$CI_COMMIT_AUTHOR =='nfc_bot '" + when: never + + # - if: # Occur on merge + # $CI_COMMIT_BRANCH == "development" + # && + # $CI_PIPELINE_SOURCE == "push" + # when: always + + - when: never + + Docker Hub: extends: .publish-docker-hub needs: - "Docker Container" + - "test:unit:docker:collection:installed" - "Gitlab Release" resource_group: docker-build rules: diff --git a/.gitlab/unit-test.gitlab-ci.yml b/.gitlab/unit-test.gitlab-ci.yml new file mode 100644 index 0000000..564d5f1 --- /dev/null +++ b/.gitlab/unit-test.gitlab-ci.yml @@ -0,0 +1,33 @@ + +.docker_collection_installed: + stage: test + image: + name: nofusscomputing/docker-buildx-qemu:dev + pull_policy: always + services: + - name: docker:23-dind + entrypoint: ["env", "-u", "DOCKER_HOST"] + command: ["dockerd-entrypoint.sh"] + variables: + DOCKER_HOST: tcp://docker:2375/ + DOCKER_DRIVER: overlay2 + DOCKER_DOCKERFILE: dockerfile + # See https://github.com/docker-library/docker/pull/166 + DOCKER_TLS_CERTDIR: "" + GIT_STRATEGY: none + + before_script: + + - | # Pull the image + docker pull $DOCKER_IMAGE_BUILD_REGISTRY/$DOCKER_IMAGE_BUILD_NAME:$DOCKER_IMAGE_BUILD_TAG; + + - | # Show local images + docker images; + + script: + + - | # Confirm the package is installed within the docker container + docker run \ + --rm \ + $DOCKER_IMAGE_BUILD_REGISTRY/$DOCKER_IMAGE_BUILD_NAME:$DOCKER_IMAGE_BUILD_TAG \ + ansible-galaxy collection list | grep nofusscomputing.phpipam_scan_agent; From de7752cfcfad58c234e3897f2654faa4451b85f3 Mon Sep 17 00:00:00 2001 From: Jon Date: Fri, 23 Feb 2024 13:24:02 +0930 Subject: [PATCH 3/8] feat(agent): move config of variables to vars file !8 closes #11 --- dockerfile | 4 +- .../collection/phpipam_scan_agent/docker.md | 9 ++- .../collection/phpipam_scan_agent/scanner.md | 38 +++++++++---- .../collection/phpipam_scan_agent/server.md | 19 ------- includes/etc/phpipam/scan_agent.yaml | 18 ++++++ playbooks/agent.yaml | 56 +++++++------------ playbooks/tasks/agent_id.yaml | 6 +- playbooks/tasks/api_call.yaml | 19 ++----- playbooks/tasks/scan_subnet.yaml | 12 ++-- playbooks/tasks/subnets.yaml | 4 +- 10 files changed, 90 insertions(+), 95 deletions(-) create mode 100644 includes/etc/phpipam/scan_agent.yaml diff --git a/dockerfile b/dockerfile index 43a8cb6..d0e923e 100644 --- a/dockerfile +++ b/dockerfile @@ -106,7 +106,9 @@ RUN mkdir -p /tmp/collection; \ /tmp/collection/.; \ rm -Rf /tmp/collection; \ fi; \ - chmod +x /etc/cron.d/*; + chmod +x /etc/cron.d/*; \ + chown root:root -R /etc/phpipam; \ + chmod 740 -R /etc/phpipam; WORKDIR /root diff --git a/docs/projects/ansible/collection/phpipam_scan_agent/docker.md b/docs/projects/ansible/collection/phpipam_scan_agent/docker.md index 80e69c6..fab0c36 100644 --- a/docs/projects/ansible/collection/phpipam_scan_agent/docker.md +++ b/docs/projects/ansible/collection/phpipam_scan_agent/docker.md @@ -23,12 +23,9 @@ docker run \ -e "MYSQL_HOST=" \ -e "MYSQL_USER=" \ -e "MYSQL_PASSWORD=" \ - -e "SCANNER_TOKEN=" \ - -e "SCANNER_NAME=" \ - -e "SCANNER_CODE=" \ -p "5000:5000" \ --name scan-agent \ - scan-agent:latest; + nofusscomputing/phpipam-scan-agent:latest; ``` @@ -44,7 +41,9 @@ During the build of the container environmental variable `ANSIBLE_FORCE_COLOR='t ### Volumes -There are no volumes for this container. +You will need to configure the scan components: + +- scanner config file at path `/etc/phpipam/scan_agent.yaml`, see [scanner docs](scanner.md#variables) for details. If you wish to customize the cronjob for the scan component within the container, mount a new cron file to path `/etc/cron.d/scanner`. The default cron file is as follows: diff --git a/docs/projects/ansible/collection/phpipam_scan_agent/scanner.md b/docs/projects/ansible/collection/phpipam_scan_agent/scanner.md index 095a910..7a0cb33 100644 --- a/docs/projects/ansible/collection/phpipam_scan_agent/scanner.md +++ b/docs/projects/ansible/collection/phpipam_scan_agent/scanner.md @@ -11,15 +11,11 @@ The Scan Agent Scanner component is intended to scan networks that are assigned ## Usage -After installing the collection, running the agent is as simple as running the following command: +After installing the collection and configuring. Running the agent is as simple as running the following command: ``` bash -ansible-playbook nofusscomputing.phpipam_scan_agent.agent \ - --extra-vars "api_url=" \ - --extra-vars "client_token=" \ - --extra-vars "client_name=" \ - --extra-vars "scanagent_code=" +ansible-playbook nofusscomputing.phpipam_scan_agent.agent ``` @@ -33,19 +29,24 @@ The scanner component requires API access to phpIPAM. THe API user that is used, ### Variables -The variables described below, if optional the value specified here is the default value. Any variable that can be set via environmental variables have the variable name enclosed in `[]` +Variables for the scanner are set in a variables file at path `/etc/phpipam/scan_agent.yaml`. The variables described below, if optional the value specified here is the default value. ``` yaml +nofusscomputing_phpipam_scan_agent: -nfc_c_http_port: 5000 # Optional, Integer. http port to connect to the server. [HTTP_PORT] -nfc_c_http_server: http://127.0.0.1 # Optional, Integer. url with protocol of the Scan Server to connect to. [HTTP_URL] + api_url: # Mandatory, String. url with protocol of the phpIPAM API to connect to. + http_port: 5000 # Optional, Integer. http port to connect to the server. + http_server: http://127.0.0.1 # Optional, Integer. url with protocol of the Scan Server to connect to. -api_url: http://127.0.0.1 # Optional, String. url with protocol of the phpIPAM API to connect to. [API_URL] + cache_expire_time: 1800 # Optional, Integer. Time in seconds to expire the phpIPAM cache. + epoch_time_offset: 0 # optional, int. Value in seconds to offset the time +# phpIPAM Scan Agent Settings + client_token: # Mandatory, String client api token to connect to phpIPAM API [client_token] + client_name: # Mandatory, String. The scanner name as set in phpIPAM interface [client_name] + scanagent_code: # Mandatory, String. Scan Agent Code as set in phpIPAM interface [scanagent_code] -nfc_c_cache_expire_time: 1800 # Optional, Integer. Time in seconds to expire the phpIPAM cache. -nfc_c_epoch_time_offset: 0 # optional, int. Value in seconds to offset the time ``` @@ -53,6 +54,19 @@ nfc_c_epoch_time_offset: 0 # optional, int. Value in seconds to offs You can specify environmental variable `ANSIBLE_LOG_PATH=/var/log/ansible.log`, which will tell the scanner component to log to a file at path `/var/log/ansible.log` +#### phpIPAM Interface variable Mapping + +These images are of the phpIPAM interface that show in green text the variable name that would be set as detailed above. + +![phpIPAM API](images/phpipam_api.png) +phpIPAM API Settings + +---- + +![phpIPAM Scan Agent](images/phpipam_scan_agent_details.png) +phpIPAM Scan Agent Settings + + ## Workflow The scanner component has the following workflow: diff --git a/docs/projects/ansible/collection/phpipam_scan_agent/server.md b/docs/projects/ansible/collection/phpipam_scan_agent/server.md index b34b6c2..a5713ae 100644 --- a/docs/projects/ansible/collection/phpipam_scan_agent/server.md +++ b/docs/projects/ansible/collection/phpipam_scan_agent/server.md @@ -25,10 +25,6 @@ ansible-rulebook -r nofusscomputing.phpipam_scan_agent.agent_receive The variables described below, if optional the value specified here is the default value. All variables that are used by the server component are environmental variables that must be set before execution. Ansbible variable name is enclused in `[]` ``` bash -# phpIPAM Scan Agent Settings -SCANNER_TOKEN= # Mandatory, String client api token to connect to phpIPAM API [client_token] -SCANNER_NAME= # Mandatory, String. The scanner name as set in phpIPAM interface [client_name] -SCANNER_CODE= # Mandatory, String. Scan Agent Code as set in phpIPAM interface [scanagent_code] # phpIPAM MariaDB/MySQL Variables MYSQL_HOST= # Mandatory, String. IP/DNS of host to connect. [nfc_c_mysql_host] @@ -43,21 +39,6 @@ HTTP_PORT=5000 # Optional, Integer. The port for the Server component to ``` -#### phpIPAM Interface variable Mapping - -These images are of the phpIPAM interface that show in green text the variable name that would be set as detailed above. - -![phpIPAM API](images/phpipam_api.png) - -phpIPAM API Settings - ----- - -![phpIPAM Scan Agent](images/phpipam_scan_agent_details.png) - -phpIPAM Scan Agent Settings - - # Workflow The Server componet has the following workflow: diff --git a/includes/etc/phpipam/scan_agent.yaml b/includes/etc/phpipam/scan_agent.yaml new file mode 100644 index 0000000..3591368 --- /dev/null +++ b/includes/etc/phpipam/scan_agent.yaml @@ -0,0 +1,18 @@ +--- + +nofusscomputing_phpipam_scan_agent: + + # api_url: http://127.0.0.1 # Mandatory, String. url with protocol of the phpIPAM API to connect to. + + # http_port: 5000 # Optional, Integer. http port to connect to the server. + # http_server: http://127.0.0.1 # Optional, Integer. url with protocol of the Scan Server to connect to. + + + # cache_expire_time: 1800 # Optional, Integer. Time in seconds to expire the phpIPAM cache. + # epoch_time_offset: 0 # optional, int. Value in seconds to offset the time + + +# phpIPAM Scan Agent Settings + client_token: # Mandatory, String client api token to connect to phpIPAM API [client_token] + client_name: # Mandatory, String. The scanner name as set in phpIPAM interface [client_name] + scanagent_code: # Mandatory, String. Scan Agent Code as set in phpIPAM interface [scanagent_code] diff --git a/playbooks/agent.yaml b/playbooks/agent.yaml index 7c33f2c..a3f4293 100644 --- a/playbooks/agent.yaml +++ b/playbooks/agent.yaml @@ -5,64 +5,48 @@ tasks: + - name: Check for Existance of config file + ansible.builtin.stat: + path: /etc/phpipam/scan_agent.yaml + register: config_file_check - - name: Fetch Required Environmental Variables - ansible.builtin.set_fact: - client_token: "{{ lookup('ansible.builtin.env', 'SCANNER_TOKEN') | default('') }}" - client_name: "{{ lookup('ansible.builtin.env', 'SCANNER_NAME') }}" - scanagent_code: "{{ lookup('ansible.builtin.env', 'SCANNER_CODE') | default('') }}" - api_url: "{{ lookup('ansible.builtin.env', 'API_URL') | default('') }}" - no_log: true + + - name: Load Config File + ansible.builtin.include_vars: + file: /etc/phpipam/scan_agent.yaml when: > - client_token is not defined - and - client_name is not defined - and - scanagent_code is not defined - and - api_url is not defined - - - - name: Fetch Required Environmental Variable - HTTP_URL - ansible.builtin.set_fact: - nfc_c_http_server: "{{ lookup('ansible.builtin.env', 'HTTP_URL') | default('') }}" - when: > - lookup('ansible.builtin.env', 'HTTP_URL') | default('') != '' - - - - name: Fetch Required Environmental Variable - HTTP_PORT - ansible.builtin.set_fact: - nfc_c_http_port: "{{ lookup('ansible.builtin.env', 'HTTP_PORT') | default('') }}" - when: > - lookup('ansible.builtin.env', 'HTTP_PORT') | default('') != '' + config_file_check.stat.exists - name: Confirm 'api_url' is Set ansible.builtin.assert: that: - - api_url is defined - - api_url != '' + - nofusscomputing_phpipam_scan_agent.api_url is defined + - nofusscomputing_phpipam_scan_agent.api_url != '' msg: "missing Required Variables" - name: Confirm 'client_token' is Set ansible.builtin.assert: that: - - client_token is defined + - nofusscomputing_phpipam_scan_agent.client_token is defined + - nofusscomputing_phpipam_scan_agent.client_token != '' msg: "missing Required Variables" - name: Confirm 'client_name' is Set ansible.builtin.assert: that: - - client_name is defined + - nofusscomputing_phpipam_scan_agent.client_name is defined + - nofusscomputing_phpipam_scan_agent.client_name != '' msg: "missing Required Variables" - name: Confirm 'scanagent_code' is Set ansible.builtin.assert: that: - - scanagent_code is defined + - nofusscomputing_phpipam_scan_agent.scanagent_code is defined + - nofusscomputing_phpipam_scan_agent.scanagent_code != '' msg: "missing Required Variables" @@ -89,12 +73,12 @@ loop_var: subnet - vars: # ToDo: remove the below t4est vars + vars: + nfc_c_cache_expire_time: 1800 nfc_c_http_port: 5000 nfc_c_http_server: http://127.0.0.1 + nfc_c_path_cache: "{{ playbook_dir }}/../cache" api_address: addresses api_subnets: subnets api_scanagents: tools/scanagents - nfc_c_path_cache: "{{ playbook_dir }}/../cache" - nfc_c_cache_expire_time: 1800 diff --git a/playbooks/tasks/agent_id.yaml b/playbooks/tasks/agent_id.yaml index 2bd20d3..1732a69 100644 --- a/playbooks/tasks/agent_id.yaml +++ b/playbooks/tasks/agent_id.yaml @@ -4,10 +4,10 @@ ansible.builtin.include_tasks: file: tasks/api_call.yaml vars: - api_client_name: "{{ client_name }}" - api_token: "{{ client_token }}" + api_client_name: "{{ nofusscomputing_phpipam_scan_agent.client_name }}" + api_token: "{{ nofusscomputing_phpipam_scan_agent.client_token }}" api_path: "{{ api_scanagents }}" - api_query_string: "filter_by=code&filter_value={{ scanagent_code }}" + api_query_string: "filter_by=code&filter_value={{ nofusscomputing_phpipam_scan_agent.scanagent_code }}" - name: My ScanAgent ID diff --git a/playbooks/tasks/api_call.yaml b/playbooks/tasks/api_call.yaml index 3a537b8..0e1b216 100644 --- a/playbooks/tasks/api_call.yaml +++ b/playbooks/tasks/api_call.yaml @@ -3,15 +3,6 @@ block: - - name: Mandatory Variables set - ansible.builtin.assert: - that: - - api_client_name is defined - - api_path is defined - - api_token is defined - - api_url is defined - - - name: API Facts ansible.builtin.set_fact: epoch: "{{ ((('%Y-%m-%d %H:%M:%S' | strftime) | string | to_datetime) - ('1970-01-01 00:00:00' | to_datetime)).total_seconds() | int }}" @@ -31,7 +22,8 @@ - name: Expire ansible.builtin.set_fact: - expired: "{{ ((epoch | int + (nfc_c_epoch_time_offset | default(0)) | int) >= ((cached_file.stat.mtime | int) + nfc_c_cache_expire_time | int) | int ) | bool }}" + expired: "{{ ((epoch | int + (nfc_c_epoch_time_offset | default(0)) | int) >= ((cached_file.stat.mtime | int) + + (nofusscomputing_phpipam_scan_agent.cache_expire_time | default(nfc_c_cache_expire_time)) | int) | int ) | bool }}" when: cached_file.stat.exists @@ -40,8 +32,9 @@ msg: - "exists: {{ cached_file.stat.exists | default('') }}" - "mtime: {{ cached_file.stat.mtime | default(0) | int }}" - - "expire: {{ (cached_file.stat.mtime | int) + nfc_c_cache_expire_time | int }}" - - "epoch: {{ (epoch | int + (nfc_c_epoch_time_offset | default(0)) | int) | int }} [{{ nfc_c_cache_expire_time }}]" + - "expire: {{ (cached_file.stat.mtime | int) + (nofusscomputing_phpipam_scan_agent.cache_expire_time | default(nfc_c_cache_expire_time)) | int }}" + - "epoch: {{ (epoch | int + (nfc_c_epoch_time_offset | default(0)) | int) | int }} [{{ + (nofusscomputing_phpipam_scan_agent.cache_expire_time | default(nfc_c_cache_expire_time)) }}]" - "epoch: {{ epoch }}" - "expired: {{ expired }}" when: cached_file.stat.exists @@ -62,7 +55,7 @@ {%- endif %} ansible.builtin.uri: url: >- - {{ api_url }}/api/{{ api_client_name }}/{{ api_path }} + {{ nofusscomputing_phpipam_scan_agent.api_url }}/api/{{ api_client_name }}/{{ api_path }} {%- if api_query_string is defined -%} /?{{ api_query_string }} {%- endif %} diff --git a/playbooks/tasks/scan_subnet.yaml b/playbooks/tasks/scan_subnet.yaml index 25ebcd8..4602786 100644 --- a/playbooks/tasks/scan_subnet.yaml +++ b/playbooks/tasks/scan_subnet.yaml @@ -5,12 +5,14 @@ cmd: nmap -sn "{{ subnet.address }}" -oX - become: true register: nmap_scan + + - name: Get subnets Address' ansible.builtin.include_tasks: file: tasks/api_call.yaml vars: - api_client_name: "{{ client_name }}" - api_token: "{{ client_token }}" + api_client_name: "{{ nofusscomputing_phpipam_scan_agent.client_name }}" + api_token: "{{ nofusscomputing_phpipam_scan_agent.client_token }}" api_path: "{{ api_address }}" api_query_string: "filter_by=subnetId&filter_value={{ subnet.id }}" @@ -65,11 +67,13 @@ - name: Upload Scan Results - {{ subnet.address }} ansible.builtin.uri: - url: "{{ nfc_c_http_server }}:{{ nfc_c_http_port }}/" + url: "{{ + nofusscomputing_phpipam_scan_agent.http_server | default(nfc_c_http_server) + }}:{{ nofusscomputing_phpipam_scan_agent.http_port | default(nfc_c_http_port) }}/" method: POST body_format: json body: { - "code": "{{ scanagent_code }}", + "code": "{{ nofusscomputing_phpipam_scan_agent.scanagent_code }}", "scan": { "subnet": "{{ subnet.address }}", "results": "{{ subnet_scan_results }}" diff --git a/playbooks/tasks/subnets.yaml b/playbooks/tasks/subnets.yaml index 923632e..785b31c 100644 --- a/playbooks/tasks/subnets.yaml +++ b/playbooks/tasks/subnets.yaml @@ -9,8 +9,8 @@ ansible.builtin.include_tasks: file: tasks/api_call.yaml vars: - api_client_name: "{{ client_name }}" - api_token: "{{ client_token }}" + api_client_name: "{{ nofusscomputing_phpipam_scan_agent.client_name }}" + api_token: "{{ nofusscomputing_phpipam_scan_agent.client_token }}" api_path: "{{ api_subnets }}" api_query_string: "filter_by=scanAgent&filter_value={{ nfc_c_scan_agent_id }}" From 87b90bffa020dd3690b95987e559062ffa3c8fbc Mon Sep 17 00:00:00 2001 From: Jon Date: Fri, 23 Feb 2024 15:14:56 +0930 Subject: [PATCH 4/8] feat(server): move config of variables to vars file !8 #11 --- .../collection/phpipam_scan_agent/docker.md | 6 +-- .../collection/phpipam_scan_agent/server.md | 22 ++++++----- extensions/eda/rulebooks/agent_receive.yml | 2 +- includes/etc/phpipam/scan_server.yaml | 13 +++++++ includes/etc/supervisor/conf.d/rulebook.conf | 2 +- playbooks/server.yaml | 37 ++++++++++--------- playbooks/tasks/server/ipaddress.yaml | 8 ++-- playbooks/tasks/server/subnet_scan.yaml | 8 ++-- 8 files changed, 57 insertions(+), 41 deletions(-) create mode 100644 includes/etc/phpipam/scan_server.yaml diff --git a/docs/projects/ansible/collection/phpipam_scan_agent/docker.md b/docs/projects/ansible/collection/phpipam_scan_agent/docker.md index fab0c36..95012e8 100644 --- a/docs/projects/ansible/collection/phpipam_scan_agent/docker.md +++ b/docs/projects/ansible/collection/phpipam_scan_agent/docker.md @@ -19,10 +19,6 @@ Launching the docker container can be done with docker run \ -d \ - -e "API_URL=" \ - -e "MYSQL_HOST=" \ - -e "MYSQL_USER=" \ - -e "MYSQL_PASSWORD=" \ -p "5000:5000" \ --name scan-agent \ nofusscomputing/phpipam-scan-agent:latest; @@ -45,6 +41,8 @@ You will need to configure the scan components: - scanner config file at path `/etc/phpipam/scan_agent.yaml`, see [scanner docs](scanner.md#variables) for details. +- server config at path `/etc/phpipam/scan_server.yaml`, see [server docs](server.md#variables) for details. + If you wish to customize the cronjob for the scan component within the container, mount a new cron file to path `/etc/cron.d/scanner`. The default cron file is as follows: ``` yaml title="/etc/cron.d/scanner" linenums="1" diff --git a/docs/projects/ansible/collection/phpipam_scan_agent/server.md b/docs/projects/ansible/collection/phpipam_scan_agent/server.md index a5713ae..53de719 100644 --- a/docs/projects/ansible/collection/phpipam_scan_agent/server.md +++ b/docs/projects/ansible/collection/phpipam_scan_agent/server.md @@ -22,24 +22,26 @@ ansible-rulebook -r nofusscomputing.phpipam_scan_agent.agent_receive ### Variables -The variables described below, if optional the value specified here is the default value. All variables that are used by the server component are environmental variables that must be set before execution. Ansbible variable name is enclused in `[]` +The variables described below, if optional the value specified here is the default value. The variables are to be set in a variables file at path `/etc/phpipam/scan_server.yaml` -``` bash +``` yaml -# phpIPAM MariaDB/MySQL Variables -MYSQL_HOST= # Mandatory, String. IP/DNS of host to connect. [nfc_c_mysql_host] -MYSQL_PORT=3306 # Optional, Integer. port to use for connection. [nfc_c_mysql_port] -MYSQL_USER= # Mandatory, String. User to authenticate with. [nfc_c_mysql_user] -MYSQL_PASSWORD= # Mandatory, String. Password for the user to connect with. [nfc_c_mysql_password] +nofusscomputing_phpipam_scan_server: + + # phpIPAM MariaDB/MySQL Variables + mysql_host: # Mandatory, String. IP/DNS of host to connect. [nfc_c_] + mysql_port: 3306 # Optional, Integer. port to use for connection. [nfc_c_] + mysql_user: # Mandatory, String. User to authenticate with. [nfc_c_] + mysql_password: # Mandatory, String. Password for the user to connect with. [nfc_c_] -# Server Component Variables -HTTP_PORT=5000 # Optional, Integer. The port for the Server component to listen for connections. + # Server Component Variables + http_port: 5000 # Optional, Integer. The port for the Server component to listen for connections. ``` -# Workflow +## Workflow The Server componet has the following workflow: diff --git a/extensions/eda/rulebooks/agent_receive.yml b/extensions/eda/rulebooks/agent_receive.yml index 5a64137..a84d2de 100644 --- a/extensions/eda/rulebooks/agent_receive.yml +++ b/extensions/eda/rulebooks/agent_receive.yml @@ -6,7 +6,7 @@ - name: Webhook ansible.eda.webhook: host: 0.0.0.0 - port: "{{ HTTP_PORT }}" + port: "{{ nofusscomputing_phpipam_scan_server.http_port | default(5000) | int }}" rules: diff --git a/includes/etc/phpipam/scan_server.yaml b/includes/etc/phpipam/scan_server.yaml new file mode 100644 index 0000000..e8176b6 --- /dev/null +++ b/includes/etc/phpipam/scan_server.yaml @@ -0,0 +1,13 @@ +--- + +nofusscomputing_phpipam_scan_server: + +# phpIPAM MariaDB/MySQL Variables +# mysql_host: # Mandatory, String. IP/DNS of host to connect. [nfc_c_] +# mysql_port: 3306 # Optional, Integer. port to use for connection. [nfc_c_] +# mysql_user: # Mandatory, String. User to authenticate with. [nfc_c_] +# mysql_password: # Mandatory, String. Password for the user to connect with. [nfc_c_] + + +# Server Component Variables +# http_port: 5000 # Optional, Integer. The port for the Server component to listen for connections. diff --git a/includes/etc/supervisor/conf.d/rulebook.conf b/includes/etc/supervisor/conf.d/rulebook.conf index c63aed3..862a8bb 100644 --- a/includes/etc/supervisor/conf.d/rulebook.conf +++ b/includes/etc/supervisor/conf.d/rulebook.conf @@ -1,7 +1,7 @@ [program:rulebook] startsecs=0 stopwaitsecs=55 -command=ansible-rulebook -r nofusscomputing.phpipam_scan_agent.agent_receive --env-vars "HTTP_PORT" -i /root/hosts.yaml -v +command=ansible-rulebook -r nofusscomputing.phpipam_scan_agent.agent_receive --vars /etc/phpipam/scan_server.yaml -i /root/hosts.yaml -v autorestart=true autostart=true stdout_logfile=/dev/fd/1 diff --git a/playbooks/server.yaml b/playbooks/server.yaml index dc41f9b..d740d90 100644 --- a/playbooks/server.yaml +++ b/playbooks/server.yaml @@ -7,26 +7,29 @@ tasks: - - name: Fetch Required Environmental Variables - ansible.builtin.set_fact: - nfc_c_mysql_host: "{{ lookup('ansible.builtin.env', 'MYSQL_HOST') | default('') }}" - nfc_c_mysql_port: "{{ lookup('ansible.builtin.env', 'MYSQL_PORT') | default(3306) | int }}" - nfc_c_mysql_user: "{{ lookup('ansible.builtin.env', 'MYSQL_USER') | default('') }}" - nfc_c_mysql_password: "{{ lookup('ansible.builtin.env', 'MYSQL_PASSWORD') | default('') }}" - no_log: true - - - name: TRACE Inbound data Received ansible.builtin.debug: msg: "{{ inbound_data }}" + - name: Check for Existance of config file + ansible.builtin.stat: + path: /etc/phpipam/scan_server.yaml + register: config_file_check + + + - name: Load Config File + ansible.builtin.include_vars: + file: /etc/phpipam/scan_server.yaml + when: > + config_file_check.stat.exists + - name: Fetch Agent Details community.mysql.mysql_query: - login_host: "{{ nfc_c_mysql_host }}" - login_port: "{{ nfc_c_mysql_port | default(3306) | int }}" - login_user: "{{ nfc_c_mysql_user }}" - login_password: "{{ nfc_c_mysql_password }}" + login_host: "{{ nofusscomputing_phpipam_scan_server.mysql_host }}" + login_port: "{{ nofusscomputing_phpipam_scan_server.mysql_port | default(3306) | int }}" + login_user: "{{ nofusscomputing_phpipam_scan_server.mysql_user }}" + login_password: "{{ nofusscomputing_phpipam_scan_server.mysql_password }}" login_db: 'phpipam' query: > @@ -37,10 +40,10 @@ - name: Confirm Subnet Assignment community.mysql.mysql_query: - login_host: "{{ nfc_c_mysql_host }}" - login_port: "{{ nfc_c_mysql_port | default(3306) | int }}" - login_user: "{{ nfc_c_mysql_user }}" - login_password: "{{ nfc_c_mysql_password }}" + login_host: "{{ nofusscomputing_phpipam_scan_server.mysql_host }}" + login_port: "{{ nofusscomputing_phpipam_scan_server.mysql_port | default(3306) | int }}" + login_user: "{{ nofusscomputing_phpipam_scan_server.mysql_user }}" + login_password: "{{ nofusscomputing_phpipam_scan_server.mysql_password }}" login_db: 'phpipam' query: > diff --git a/playbooks/tasks/server/ipaddress.yaml b/playbooks/tasks/server/ipaddress.yaml index 633ae0c..fb80058 100644 --- a/playbooks/tasks/server/ipaddress.yaml +++ b/playbooks/tasks/server/ipaddress.yaml @@ -3,10 +3,10 @@ - name: "Update IP Address' found - {{ scan_address.ipaddress.ip }}" community.mysql.mysql_query: - login_host: "{{ nfc_c_mysql_host }}" - login_port: "{{ nfc_c_mysql_port | default(3306) | int }}" - login_user: "{{ nfc_c_mysql_user }}" - login_password: "{{ nfc_c_mysql_password }}" + login_host: "{{ nofusscomputing_phpipam_scan_server.mysql_host }}" + login_port: "{{ nofusscomputing_phpipam_scan_server.mysql_port | default(3306) | int }}" + login_user: "{{ nofusscomputing_phpipam_scan_server.mysql_user }}" + login_password: "{{ nofusscomputing_phpipam_scan_server.mysql_password }}" login_db: 'phpipam' query: |- diff --git a/playbooks/tasks/server/subnet_scan.yaml b/playbooks/tasks/server/subnet_scan.yaml index d9eb038..a8de9f5 100644 --- a/playbooks/tasks/server/subnet_scan.yaml +++ b/playbooks/tasks/server/subnet_scan.yaml @@ -3,10 +3,10 @@ - name: Match Scan Addresses to DB Details community.mysql.mysql_query: - login_host: "{{ nfc_c_mysql_host }}" - login_port: "{{ nfc_c_mysql_port | default(3306) | int }}" - login_user: "{{ nfc_c_mysql_user }}" - login_password: "{{ nfc_c_mysql_password }}" + login_host: "{{ nofusscomputing_phpipam_scan_server.mysql_host }}" + login_port: "{{ nofusscomputing_phpipam_scan_server.mysql_port | default(3306) | int }}" + login_user: "{{ nofusscomputing_phpipam_scan_server.mysql_user }}" + login_password: "{{ nofusscomputing_phpipam_scan_server.mysql_password }}" login_db: 'phpipam' query: |- From a72b9fc8eb5d5b038e87412336db3f59b83d7ca9 Mon Sep 17 00:00:00 2001 From: Jon Date: Fri, 23 Feb 2024 16:05:58 +0930 Subject: [PATCH 5/8] feat(server): update subnet discovery date/time !9 closes #12 --- .../collection/phpipam_scan_agent/server.md | 5 +++++ playbooks/tasks/server/subnet_scan.yaml | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/docs/projects/ansible/collection/phpipam_scan_agent/server.md b/docs/projects/ansible/collection/phpipam_scan_agent/server.md index 53de719..175acb9 100644 --- a/docs/projects/ansible/collection/phpipam_scan_agent/server.md +++ b/docs/projects/ansible/collection/phpipam_scan_agent/server.md @@ -56,3 +56,8 @@ The Server componet has the following workflow: - _if no results found, no further processing occurs_ 1. Update the phpIPAM MariaDB/MySQL database directly + + +## phpIPAM Features + +- **Last discovery time** This is displayed within the subnet interface next to the `Discover new hosts` fieled. Whenever a scan report is received by the server this filed is updated to reflect the last scan time. diff --git a/playbooks/tasks/server/subnet_scan.yaml b/playbooks/tasks/server/subnet_scan.yaml index a8de9f5..c7d4f33 100644 --- a/playbooks/tasks/server/subnet_scan.yaml +++ b/playbooks/tasks/server/subnet_scan.yaml @@ -26,6 +26,24 @@ loop_var: ipaddress +- name: Update Subnet Discovery Time + community.mysql.mysql_query: + login_host: "{{ nofusscomputing_phpipam_scan_server.mysql_host }}" + login_port: "{{ nofusscomputing_phpipam_scan_server.mysql_port | default(3306) | int }}" + login_user: "{{ nofusscomputing_phpipam_scan_server.mysql_user }}" + login_password: "{{ nofusscomputing_phpipam_scan_server.mysql_password }}" + + login_db: 'phpipam' + query: |- + UPDATE + subnets + SET + lastDiscovery = '{{ inbound_data.scan.results[0].lastSeen }}' + WHERE + subnet = '{{ (inbound_data.scan.subnet | split('/'))[0] | ip2ipam }}' + single_transaction: true + + - name: Update IP Addresses ansible.builtin.include_tasks: file: tasks/server/ipaddress.yaml From 5ca5b98b383ecf4e629f9ff197e237f47bd654da Mon Sep 17 00:00:00 2001 From: Jon Date: Fri, 23 Feb 2024 16:57:16 +0930 Subject: [PATCH 6/8] refactor(server): don't process scan results in parallel !9 --- extensions/eda/rulebooks/agent_receive.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/eda/rulebooks/agent_receive.yml b/extensions/eda/rulebooks/agent_receive.yml index a84d2de..35aac33 100644 --- a/extensions/eda/rulebooks/agent_receive.yml +++ b/extensions/eda/rulebooks/agent_receive.yml @@ -1,6 +1,5 @@ - name: Agent Webhook hosts: all - execution_strategy: parallel sources: - name: Webhook From c41be4541e4b650c38a6af203583436adcd60c78 Mon Sep 17 00:00:00 2001 From: Jon Date: Fri, 23 Feb 2024 17:00:17 +0930 Subject: [PATCH 7/8] docs: clean up !9 --- .../collection/phpipam_scan_agent/docker.md | 2 ++ .../ansible/collection/phpipam_scan_agent/index.md | 14 +++++++------- .../collection/phpipam_scan_agent/server.md | 5 ----- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/docs/projects/ansible/collection/phpipam_scan_agent/docker.md b/docs/projects/ansible/collection/phpipam_scan_agent/docker.md index 95012e8..c990645 100644 --- a/docs/projects/ansible/collection/phpipam_scan_agent/docker.md +++ b/docs/projects/ansible/collection/phpipam_scan_agent/docker.md @@ -20,6 +20,8 @@ Launching the docker container can be done with docker run \ -d \ -p "5000:5000" \ + -v "./scan_agent.yaml:/etc/phpipam/scan_agent.yaml" \ + -v "./scan_server.yaml:/etc/phpipam/scan_server.yaml" \ --name scan-agent \ nofusscomputing/phpipam-scan-agent:latest; diff --git a/docs/projects/ansible/collection/phpipam_scan_agent/index.md b/docs/projects/ansible/collection/phpipam_scan_agent/index.md index 76b9973..16a2b74 100644 --- a/docs/projects/ansible/collection/phpipam_scan_agent/index.md +++ b/docs/projects/ansible/collection/phpipam_scan_agent/index.md @@ -68,6 +68,11 @@ When this setting is enabled, the scanner will scan the entire subnet that has b the work in [Hosts check](https://gitlab.com/nofusscomputing/projects/ansible/collections/phpipam_scan_agent/-/issues/3), will adjust this behaviour to only add hosts that dont exist. + - Location `Subnet -> Discover new hosts [Last discovery time]` + +This is displayed within the subnet interface next to the `Discover new hosts` field. Whenever a scan report is received by the server this filed is updated to reflect the last scan time. + + ## Development Notes Contributions to this project are welcome. Below you will find some useful commands for use during development. @@ -80,13 +85,8 @@ docker build . --tag scan-agent:dev --build-arg COLLECTION_BRANCH=" \ - -e "MYSQL_HOST=" \ - -e "MYSQL_USER=" \ - -e "MYSQL_PASSWORD=" \ - -e "SCANNER_TOKEN=" \ - -e "SCANNER_NAME=" \ - -e "SCANNER_CODE=" \ + -v "./scan_agent.yaml:/etc/phpipam/scan_agent.yaml" \ + -v "./scan_server.yaml:/etc/phpipam/scan_server.yaml" \ -e "ANSIBLE_LOG_PATH=/var/log/ansible.log" \ -p "5000:5000" \ --name scan-agent \ diff --git a/docs/projects/ansible/collection/phpipam_scan_agent/server.md b/docs/projects/ansible/collection/phpipam_scan_agent/server.md index 175acb9..53de719 100644 --- a/docs/projects/ansible/collection/phpipam_scan_agent/server.md +++ b/docs/projects/ansible/collection/phpipam_scan_agent/server.md @@ -56,8 +56,3 @@ The Server componet has the following workflow: - _if no results found, no further processing occurs_ 1. Update the phpIPAM MariaDB/MySQL database directly - - -## phpIPAM Features - -- **Last discovery time** This is displayed within the subnet interface next to the `Discover new hosts` fieled. Whenever a scan report is received by the server this filed is updated to reflect the last scan time. From d9885ef78b19d8596a8b6cfe9a20921d5b20f968 Mon Sep 17 00:00:00 2001 From: Jon Date: Fri, 23 Feb 2024 17:33:06 +0930 Subject: [PATCH 8/8] docs: badge rearrangement !9 --- README.md | 20 +++++-------------- .../collection/phpipam_scan_agent/index.md | 10 ++++++---- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index f77c965..c7f27b6 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,13 @@ - + # No Fuss Computing - Ansible Collection PHPIPAM Scan Agent ![Project Status - Active](https://img.shields.io/badge/Project%20Status-Active-green?logo=gitlab&style=plastic) +[![Downloads](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgalaxy.ansible.com%2Fapi%2Fv3%2Fplugin%2Fansible%2Fcontent%2Fpublished%2Fcollections%2Findex%2Fnofusscomputing%2Fphpipam_scan_agent%2F&query=%24.download_count&style=plastic&logo=ansible&logoColor=white&label=Galaxy%20Downloads&labelColor=black&color=cyan)](https://galaxy.ansible.com/ui/repo/published/nofusscomputing/phpipam_scan_agent/) +[![Docker Pulls](https://img.shields.io/docker/pulls/nofusscomputing/phpipam-scan-agent?style=plastic&logo=docker&logoColor=0db7ed&color=0db7ed)](https://hub.docker.com/r/nofusscomputing/phpipam-scan-agent) + + ----
@@ -28,20 +32,6 @@ This project is hosted on [gitlab](https://gitlab.com/nofusscomputing/projects/a ![Gitlab build status - development](https://img.shields.io/badge/dynamic/json?color=ff782e&label=Build&query=0.status&url=https%3A%2F%2Fgitlab.com%2Fapi%2Fv4%2Fprojects%2F55052132%2Fpipelines%3Fref%3Ddevelopment&logo=gitlab&style=plastic) ![branch release version](https://img.shields.io/badge/dynamic/yaml?color=ff782e&logo=gitlab&style=plastic&label=Release&query=%24.commitizen.version&url=https%3A//gitlab.com/nofusscomputing/projects/ansible/collections/phpipam_scan_agent%2F-%2Fraw%2Fdevelopment%2F.cz.yaml) ----- - -**Ansible Galaxy** - -[![Latest Version](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgalaxy.ansible.com%2Fapi%2Fv3%2Fplugin%2Fansible%2Fcontent%2Fpublished%2Fcollections%2Findex%2Fnofusscomputing%2Fphpipam_scan_agent%2F&query=%24.highest_version.version&style=plastic&logo=ansible&logoColor=white&label=Latest%20Release&labelColor=black&color=cyan)](https://galaxy.ansible.com/ui/repo/published/nofusscomputing/phpipam_scan_agent/) -![Downloads](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgalaxy.ansible.com%2Fapi%2Fv3%2Fplugin%2Fansible%2Fcontent%2Fpublished%2Fcollections%2Findex%2Fnofusscomputing%2Fphpipam_scan_agent%2F&query=%24.download_count&style=plastic&logo=ansible&logoColor=white&label=Downloads&labelColor=black&color=cyan) - ----- - -**Docker Hub** - -[![Docker Image Version](https://img.shields.io/docker/v/nofusscomputing/phpipam-scan-agent?sort=semver&style=plastic&logo=docker&logoColor=0db7ed&color=0db7ed&label=Latest%20Release)](https://hub.docker.com/r/nofusscomputing/phpipam-scan-agent) -[![Docker Pulls](https://img.shields.io/docker/pulls/nofusscomputing/phpipam-scan-agent?style=plastic&logo=docker&logoColor=0db7ed&color=0db7ed)](https://hub.docker.com/r/nofusscomputing/phpipam-scan-agent) -
---- diff --git a/docs/projects/ansible/collection/phpipam_scan_agent/index.md b/docs/projects/ansible/collection/phpipam_scan_agent/index.md index 16a2b74..8a84a18 100644 --- a/docs/projects/ansible/collection/phpipam_scan_agent/index.md +++ b/docs/projects/ansible/collection/phpipam_scan_agent/index.md @@ -6,14 +6,16 @@ template: project.html about: https://gitlab.com/nofusscomputing/projects/ansible/collections/phpipam_scan_agent --- - + ![Project Status - Active](https://img.shields.io/badge/Project%20Status-Active-green?logo=gitlab&style=plastic) -[![Latest Version](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgalaxy.ansible.com%2Fapi%2Fv3%2Fplugin%2Fansible%2Fcontent%2Fpublished%2Fcollections%2Findex%2Fnofusscomputing%2Fphpipam_scan_agent%2F&query=%24.highest_version.version&style=plastic&logo=ansible&logoColor=white&label=Latest%20Release&labelColor=black&color=cyan)](https://galaxy.ansible.com/ui/repo/published/nofusscomputing/phpipam_scan_agent/) -![Downloads](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgalaxy.ansible.com%2Fapi%2Fv3%2Fplugin%2Fansible%2Fcontent%2Fpublished%2Fcollections%2Findex%2Fnofusscomputing%2Fphpipam_scan_agent%2F&query=%24.download_count&style=plastic&logo=ansible&logoColor=white&label=Downloads&labelColor=black&color=cyan) -[![Docker Image Version](https://img.shields.io/docker/v/nofusscomputing/phpipam-scan-agent?sort=semver&style=plastic&logo=docker&logoColor=0db7ed&color=0db7ed&label=Latest%20Release)](https://hub.docker.com/r/nofusscomputing/phpipam-scan-agent) +![branch release version](https://img.shields.io/badge/dynamic/yaml?color=ff782e&logo=gitlab&style=plastic&label=Stable%20Release&query=%24.commitizen.version&url=https%3A//gitlab.com/nofusscomputing/projects/ansible/collections/phpipam_scan_agent%2F-%2Fraw%2Fmaster%2F.cz.yaml) +![branch release version](https://img.shields.io/badge/dynamic/yaml?color=ff782e&logo=gitlab&style=plastic&label=Dev%20Release&query=%24.commitizen.version&url=https%3A//gitlab.com/nofusscomputing/projects/ansible/collections/phpipam_scan_agent%2F-%2Fraw%2Fdevelopment%2F.cz.yaml) + + +[![Downloads](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgalaxy.ansible.com%2Fapi%2Fv3%2Fplugin%2Fansible%2Fcontent%2Fpublished%2Fcollections%2Findex%2Fnofusscomputing%2Fphpipam_scan_agent%2F&query=%24.download_count&style=plastic&logo=ansible&logoColor=white&label=Galaxy%20Downloads&labelColor=black&color=cyan)](https://galaxy.ansible.com/ui/repo/published/nofusscomputing/phpipam_scan_agent/) [![Docker Pulls](https://img.shields.io/docker/pulls/nofusscomputing/phpipam-scan-agent?style=plastic&logo=docker&logoColor=0db7ed&color=0db7ed)](https://hub.docker.com/r/nofusscomputing/phpipam-scan-agent)