project: releng/ciman
stream: latest
build-node: build-vm
-
- view-regex: '{project-name}-.*'
- view-description: 'List of {project-name} jobs'
project-name: gerrit-ciman
+ jenkins-urls: >
+ https://jenkins.example.org
+ https://jenkins.example.org/sandbox
+
- project:
name: github-openstack-jobs
jobs:
project-name: github-ciman
+ jenkins-urls: >
+ https://jenkins.example.org
+ https://jenkins.example.org/sandbox
+
- project:
name: gerrit-packer-jobs
- project:
name: ci-jobs-view
- project-name: ci-jobs
views:
- - common-view
- view-regex: '.*-ci-jobs$|.*-openstack-jobs$|.*-packer-jobs$'
- view-description: 'List of ci-jobs, openstack and packer jobs'
+ - project-view
+
+ project-name: ci-jobs
- 'gerrit-jenkins-cfg-merge'
project-name: ci-management
-
-- project:
- name: jenkins-cfg-jobs-view
- project-name: jenkins-cfg
- views:
- - common-view
- view-regex: '^jenkins-cfg.*'
- view-description: 'List of jenkins-cfg jobs'
--- /dev/null
+---
+- project:
+ name: jenkins-cfg-verify
+ jobs:
+ - "gerrit-jenkins-cfg-verify"
+
+ project-name: ci-management
--- /dev/null
+---
+- project:
+ name: openstack-cron-full-test
+ jobs:
+ - 'gerrit-openstack-cron'
+
+ project-name: ciman-full
+
+ jenkins-urls: >
+ https://jenkins.example.org
+ https://jenkins.example.org/sandbox
+ openstack-cloud: example-cloud
+ openstack-image-cleanup: false
+ openstack-image-cleanup-age: 42
+ openstack-image-protect: false
+ openstack-server-cleanup: false
+ openstack-stack-cleanup: false
+ openstack-volume-cleanup: false
--- /dev/null
+---
+- project:
+ name: openstack-cron-minimal-test
+ jobs:
+ - 'gerrit-openstack-cron'
+
+ project-name: ci-management
+
+ jenkins-urls: >
+ https://jenkins.example.org
+ https://jenkins.example.org/sandbox
--- /dev/null
+---
+- project:
+ name: common-view-test
+ views:
+ - common-view
+
+ view-name: Daily
+ view-regex: '.*-daily-.*'
--- /dev/null
+---
+- project:
+ name: csit-view-test
+ views:
+ - csit-view
+
+ view-name: CSIT-1node
+ view-regex: '.*csit-1node.*'
- project:
name: maven-jobs-view
- project-name: maven
views:
- - common-view
- view-regex: '.*-maven$'
- view-description: 'List of maven jobs'
+ - project-view
+
+ project-name: maven
- project:
name: node-jobs-view
- project-name: node
views:
- - common-view
- view-regex: '.*-node$'
- view-description: 'List of node jobs'
+ - project-view
+
+ project-name: node
- project:
name: openstack-jobs-view
- project-name: openstack
views:
- - common-view
- view-regex: '.*-openstack$'
- view-description: 'List of openstack jobs'
+ - project-view
+
+ project-name: openstack
--- /dev/null
+---
+- project:
+ name: project-view-test
+ views:
+ - project-view
+
+ project-name: project-view-test
- project:
name: python-jobs-view
- project-name: python
views:
- - common-view
- view-regex: '.*-python$'
- view-description: 'List of Python jobs'
+ - project-view
+
+ project-name: python
- project:
name: rtd-jobs-view
- project-name: rtd
views:
- - common-view
- view-regex: '.*-rtd$'
- view-description: 'List of rtd jobs'
+ - project-view
+
+ project-name: rtd
used to push to Jenkins. In the event of a job failure this file can be
inspected.
+ .. _lf-global-jjb-jenkins-cfg-verify:
+
+Jenkins Configuration Verify
+----------------------------
+
+Jenkins job to verify the Global Jenkins configuration.
+
+Requires the ``clouds-yaml`` file to be setup on the Jenkins host.
+
+:Template names:
+
+ - {project-name}-jenkins-cfg-verify
+ - gerrit-jenkins-cfg-verify
+ - github-jenkins-cfg-verify
+
+:Optional parameters:
+
+ :branch: Git branch to build against. (default: master)
+ :git-url: URL to clone project from. (default: $GIT_URL/$GERRIT_PROJECT)
+
+This job is not part of the "{project-name}-ci-jobs" group. It must be called
+explicitly.
+
+Example:
+
+.. literalinclude:: ../../.jjb-test/lf-ci-jobs/jenkins-cfg-verify.yaml
+ :language: yaml
Jenkins Sandbox Cleanup
-----------------------
:build-node: The node to run build on.
:jenkins-ssh-credential: Credential to use for SSH. (Generally should
be configured in defaults.yaml)
+ :jenkins-urls: URLs to Jenkins systems to check for active builds.
:Optional parameters:
:branch: Git branch to fetch for the build. (default: master)
:build-days-to-keep: Days to keep build logs in Jenkins. (default: 7)
:build-timeout: Timeout in minutes before aborting build. (default: 90)
- :cron: Time when the packer image should be rebuilt (default: @daily)
+ :cron: Time when the packer image should be rebuilt (default: @hourly)
:git-url: URL clone project from. (default: $GIT_URL/$PROJECT)
:openstack-cloud: OS_CLOUD setting to pass to openstack client.
(default: vex)
+ :openstack-image-cleanup: Whether or not to run the image cleanup script.
+ (default: true)
+ :openstack-image-cleanup-age: Age in days of image before marking it for
+ removal. (default: 30)
+ :openstack-image-protect: Whether or not to run the image protect script.
+ (default: true)
+ :openstack-server-cleanup: Whether or not to run the server cleanup script.
+ (default: true)
+ :openstack-stack-cleanup: Whether or not to run the stack cleanup script.
+ (default: true)
+ :openstack-volume-cleanup: Whether or not to run the volume cleanup script.
+ (default: true)
:stream: Keyword that can be used to represent a release code-name.
Often the same as the branch. (default: master)
:submodule-recursive: Whether to checkout submodules recursively.
:submodule-timeout: Timeout (in minutes) for checkout operation.
(default: 10)
+Minimal Example:
+
+.. literalinclude:: ../../.jjb-test/lf-ci-jobs/openstack-cron-minimal.yaml
+
+Full Example:
+
+.. literalinclude:: ../../.jjb-test/lf-ci-jobs/openstack-cron-full.yaml
+
+
.. _gjjb-packer-merge:
Packer Merge
View Templates
==============
-JJB view-templates provides a way to manage Jenkins views through code.
+JJB view-templates provides a way to manage Jenkins views through code. Using
+view-templates we can define common views configuration that are interesting
+to a project.
+We recommend creating separate project sections for views apart from job
+configuration such that job configuration does not overlap with the view
+configuration.
+
+Example Usage:
+
+.. code-block:: yaml
+
+ ---
+ - project:
+ name: project-view
+ views:
+ - common-view
+
+ project-name: project
+
+ - project:
+ name: project-stream1
+ jobs:
+ - '{project-name}-{seq}'
+
+ project: project
+ project-name: project
+ seq:
+ - a
+ - b
+
+ - project:
+ name: project-stream2
+ jobs:
+ - '{project-name}-{seq}'
+
+ project: project
+ project-name: project
+ seq:
+ - x
+ - y
+
+ - job-template:
+ name: '{project-name}-{seq}'
-Common view
------------
-Common view groups jobs related to a project and supports the following
-columns.
+Project view
+------------
+
+Groups all jobs owned by a project under one view by capturing jobs with the
+prefix of ``project-name``.
+
+This view uses the following columns:
:Columns:
- build-button
- jacoco
- find-bugs
- - robot-list
:Template Names:
- - common-view
- {project-name}
+ - project-view
:Required parameters:
- :project-name: The name of the view.
- :view-description: View description. (Generally set to 'List of
- {project-name} jobs' in defaults.yaml)
- :view-regex: Regex to match the jobs. (Generally set to '^{project-name}-.*'
- in defaults.yaml)
+ :project-name: The name of the project utilizing the view.
:Optional parameters:
:view-filter-queue: View filter queue. (default: false)
:view-recurse: View recurse. (default: false)
-Integration CSIT view
----------------------
+Example:
+
+.. literalinclude:: ../../.jjb-test/lf-project-view.yaml
+ :language: yaml
+
-Integration CSIT view provides a view for integration or CSIT jobs.
-The view supports the following set of columns.
+Common view
+-----------
+
+Groups all jobs owned by a project under one view by capturing jobs with the
+prefix of ``project-name``.
+
+This view uses the following columns:
+
+:Columns:
+
+ - status
+ - weather
+ - job
+ - last-success
+ - last-failure
+ - last-duration
+ - build-button
+ - jacoco
+ - find-bugs
+
+:Template Names:
+
+ - {view-name}
+ - common-view
+
+:Required parameters:
+
+ :view-name: The name of the view.
+ :view-regex: Regex to match the jobs.
+
+:Optional parameters:
+
+ :view-filter-executors: View filter executor. (default: false)
+ :view-filter-queue: View filter queue. (default: false)
+ :view-recurse: View recurse. (default: false)
+
+Example:
+
+.. literalinclude:: ../../.jjb-test/lf-common-view.yaml
+ :language: yaml
+
+
+CSIT view template
+------------------
+
+View template that loads columns useful for CSIT jobs.
+
+This view uses the following columns:
:Columns:
:Template Names:
- - integration-csit-view
- - {project-name}
+ - {view-name}
+ - csit-view
:Required parameters:
- :project-name: The name of the view.
- :view-description: View description. (Generally set to 'List of
- {project-name} jobs' in defaults.yaml)
- :view-regex: Regex to match the jobs. (Generally set to '^{project-name}-.*'
- in defaults.yaml)
+ :view-name: The name of the view.
+ :view-regex: Regex to match the jobs.
:Optional parameters:
+ :view-description: View description. (default: 'CSIT Jobs.')
:view-filter-executors: View filter executor. (default: false)
:view-filter-queue: View filter queue. (default: false)
:view-recurse: View recurse. (default: false)
+
+Example:
+
+.. literalinclude:: ../../.jjb-test/lf-csit-view.yaml
+ :language: yaml
white-list-target-branches:
- '{branch}'
+###########################################
+# Jenkins Configuration Management Verify #
+###########################################
+
+- lf_jenkins_configuration: &lf_jenkins_cfg_verify
+ name: lf-jenkins-cfg-verify
+
+ ######################
+ # Default parameters #
+ ######################
+
+ branch: master
+ build-days-to-keep: 7
+ disable-job: false
+ git-url: '$GIT_URL/$GERRIT_PROJECT'
+ github-url: 'https://github.com'
+ openstack-cloud: vex
+ submodule-timeout: 10
+
+ gerrit_verify_triggers:
+ - patchset-created-event:
+ exclude-drafts: true
+ exclude-trivial-rebase: false
+ exclude-no-code-change: false
+ - draft-published-event
+ - comment-added-contains-event:
+ comment-contains-value: '^Patch Set[ ]+[0-9]+:([ ]+|[\n]+)(recheck|reverify)$'
+
+ gerrit_trigger_file_paths:
+ - compare-type: REG_EXP
+ pattern: 'jenkins-config\/.*'
+
+ # github_included_regions MUST match gerrit_trigger_file_paths
+ github_included_regions:
+ - 'jenkins-config\/.*'
+
+ #####################
+ # Job Configuration #
+ #####################
+
+ project-type: freestyle
+ node: '{build-node}'
+ concurrent: true
+ disabled: '{disable-job}'
+
+ properties:
+ - lf-infra-properties:
+ project: '{project}'
+ build-days-to-keep: 1
+
+ parameters:
+ - lf-infra-parameters:
+ project: '{project}'
+ stream: ''
+ branch: master
+ lftools-version: '{lftools-version}'
+
+ wrappers:
+ - lf-infra-wrappers:
+ build-timeout: 10
+ jenkins-ssh-credential: '{jenkins-ssh-credential}'
+ - config-file-provider:
+ # Listed after to override openstack-infra-wrappers clouds.yaml
+ # definition
+ files:
+ - file-id: clouds-yaml
+ target: '$HOME/.config/openstack/clouds.yaml'
+ - file-id: npmrc
+ target: '$HOME/.npmrc'
+ - file-id: pipconf
+ target: '$HOME/.config/pip/pip.conf'
+
+ builders:
+ - lf-infra-pre-build
+ - inject:
+ properties-content: OS_CLOUD={openstack-cloud}
+ - shell: !include-raw-escape: ../shell/jenkins-verify-images.sh
+
+ publishers:
+ - lf-infra-publish
+
+- job-template:
+ name: '{project-name}-jenkins-cfg-verify'
+ id: gerrit-jenkins-cfg-verify
+ <<: *lf_jenkins_cfg_verify
+
+ scm:
+ - lf-infra-gerrit-scm:
+ git-url: '{git-url}'
+ refspec: 'refs/heads/{branch}'
+ branch: '{branch}'
+ submodule-recursive: true
+ submodule-timeout: '{submodule-timeout}'
+ choosing-strategy: default
+ jenkins-ssh-credential: '{jenkins-ssh-credential}'
+
+ triggers:
+ - gerrit:
+ server-name: '{gerrit-server-name}'
+ trigger-on: '{obj:gerrit_verify_triggers}'
+ projects:
+ - project-compare-type: ANT
+ project-pattern: '{project}'
+ branches:
+ - branch-compare-type: ANT
+ branch-pattern: '**/{branch}'
+ file-paths: '{obj:gerrit_trigger_file_paths}'
+
+- job-template:
+ name: '{project-name}-jenkins-cfg-verify'
+ id: github-jenkins-cfg-verify
+ <<: *lf_jenkins_cfg_verify
+
+ properties:
+ - github:
+ url: '{github-url}/{github-org}/{project}'
+
+ scm:
+ - lf-infra-github-scm:
+ url: '{git-clone-url}{github-org}/{project}'
+ refspec: '+refs/pull/*:refs/remotes/origin/pr/*'
+ branch: '$sha1'
+ submodule-recursive: '{submodule-recursive}'
+ submodule-timeout: '{submodule-timeout}'
+ choosing-strategy: default
+ jenkins-ssh-credential: '{jenkins-ssh-credential}'
+
+ triggers:
+ - github-pull-request:
+ trigger-phrase: '^(recheck|reverify)$'
+ only-trigger-phrase: false
+ status-context: 'Jenkins CFG Verify'
+ permit-all: true
+ github-hooks: true
+ included-regions: '{obj:github_included_regions}'
+ white-list-target-branches:
+ - '{branch}'
###########################
# JENKINS SANDBOX CLEANUP #
branch: master
build-days-to-keep: 7
build-timeout: 10
- cron: '@daily'
+ cron: '@hourly'
disable-job: false
git-url: '$GIT_URL/$PROJECT'
github-url: 'https://github.com'
openstack-cloud: vex
+ openstack-image-cleanup: true
+ openstack-image-cleanup-age: 30
+ openstack-image-protect: true
+ openstack-server-cleanup: true
+ openstack-stack-cleanup: true
+ openstack-volume-cleanup: true
stream: master
submodule-timeout: 10
stream: '{stream}'
branch: '{branch}'
lftools-version: '{lftools-version}'
+ - string:
+ name: JENKINS_URLS
+ default: '{jenkins-urls}'
+ description: |
+ Space separated list of Jenkins URLs to check for active builds.
wrappers:
- lf-infra-wrappers:
- timed: '{obj:cron}'
builders:
+ - lf-infra-pre-build
- inject:
properties-content: OS_CLOUD={openstack-cloud}
- - shell: !include-raw-escape: ../shell/openstack-install.sh
- - shell: !include-raw-escape: ../shell/openstack-protect-in-use-images.sh
+ # Stacks
+ - conditional-step:
+ condition-kind: boolean-expression
+ condition-expression: '{openstack-stack-cleanup}'
+ steps:
+ - shell: !include-raw-escape: ../shell/openstack-cleanup-orphaned-stacks.sh
+ # Servers
+ - conditional-step:
+ condition-kind: boolean-expression
+ condition-expression: '{openstack-server-cleanup}'
+ steps:
+ - shell: !include-raw-escape: ../shell/openstack-cleanup-orphaned-servers.sh
+ # Volumes
+ - conditional-step:
+ condition-kind: boolean-expression
+ condition-expression: '{openstack-volume-cleanup}'
+ steps:
+ - shell: !include-raw-escape: ../shell/openstack-cleanup-orphaned-volumes.sh
+ # Images
+ - conditional-step:
+ condition-kind: boolean-expression
+ condition-expression: '{openstack-image-protect}'
+ steps:
+ - shell: !include-raw-escape: ../shell/openstack-protect-in-use-images.sh
+ - conditional-step:
+ condition-kind: boolean-expression
+ condition-expression: '{openstack-image-cleanup}'
+ steps:
+ - inject:
+ properties-content: OS_IMAGE_CLEANUP_AGE={openstack-image-cleanup-age}
+ - shell: !include-raw-escape: ../shell/openstack-cleanup-old-images.sh
publishers:
- lf-infra-publish
# common view template #
########################
+- lf_view_common_columns: &lf_view_common_columns
+ name: lf-view-common-columns
+
+ columns:
+ - status
+ - weather
+ - job
+ - last-success
+ - last-failure
+ - last-duration
+ - build-button
+ - jacoco
+ - find-bugs
+
- view-template:
id: 'common-view'
- name: '{project-name}'
+ name: '{view-name}'
######################
# Default parameters #
######################
+ view-description: 'View using common-view template.'
view-filter-executors: false
view-filter-queue: false
view-recurse: false
######################
view-type: list
+ description: '{view-description}'
filter-executors: '{view-filter-executors}'
filter-queue: '{view-filter-queue}'
- columns:
- - status
- - weather
- - job
- - last-success
- - last-failure
- - last-duration
- - build-button
- - jacoco
- - find-bugs
- - robot-list
recurse: '{view-recurse}'
regex: '{view-regex}'
- description: '{view-description}'
+ <<: *lf_view_common_columns
-#############################
-# integration view template #
-#############################
+######################
+# CSIT view template #
+######################
- view-template:
- id: 'integration-csit-view'
- name: '{project-name}'
+ id: 'csit-view'
+ name: '{view-name}'
######################
# Default parameters #
######################
+ view-description: 'CSIT jobs.'
view-filter-executors: false
view-filter-queue: false
view-recurse: false
######################
view-type: list
+ description: '{view-description}'
filter-executors: '{view-filter-executors}'
filter-queue: '{view-filter-queue}'
+ recurse: '{view-recurse}'
+ regex: '{view-regex}'
columns:
- status
- weather
- last-duration
- build-button
- robot-list
+
+#########################
+# project view template #
+#########################
+
+- view-template:
+ id: 'project-view'
+ name: '{project-name}'
+
+ ######################
+ # Default parameters #
+ ######################
+
+ view-filter-executors: false
+ view-filter-queue: false
+ view-recurse: false
+
+ ######################
+ # view Configuration #
+ ######################
+
+ view-type: list
+ description: 'List of jobs for {project-name}.'
+ filter-executors: '{view-filter-executors}'
+ filter-queue: '{view-filter-queue}'
recurse: '{view-recurse}'
- regex: '{view-regex}'
- description: '{view-description}'
+ regex: '^{project-name}-.*'
+ <<: *lf_view_common_columns
---
features:
- |
- New view-templates ``common-view`` and ``integration-csit-view`` are
+ New view-templates ``project-view``, ``common-view``, and ``csit-view`` are
available for projects to manage Jenkins views through code.
- To use the ``common-view`` template in a project.
-
- Usage:
+ To use the ``project-view`` template in a project:
.. code-block:: yaml
- project:
- ...
+ name: aaa-view
views:
- - common-view
+ - project-view
- To use the ``integration-csit-view`` template in a project.
+ project-name: aaa
- Usage:
+ To use the ``common-view`` template in a project:
.. code-block:: yaml
- project:
- ...
+ name: daily-builds
views:
- - integration-csit-view
+ - common-view
- - |
- A separate project section can be defined for views that are common to a
- set of jobs. This creates a list-type view with ``<project-name>`` in
- Jenkins which lists all the jobs under the view.
+ view-name: Periodic
+ view-regex: '.*-periodic-.*'
- Usage:
+ To use the ``csit-view`` template in a project:
.. code-block:: yaml
- project:
- name: <project-name-view>
- project: <project>
- project-name: <project-name>
+ name: csit
views:
- - common-view
-
- Example Usage:
+ - csit-view
- .. code-block:: yaml
-
- ---
- - defaults:
- name: global
- view-regex: '^{project-name}-.*'
- view-description: 'default view description'
+ view-name: CSIT
+ view-regex: '.*csit.*'
- project:
- name: project-view
- project: project
- project-name: project
+ name: csit-1node
views:
- - common-view
-
- - project:
- name: project-stream1
- project: project
- project-name: project
- jobs:
- - '{project-name}-{seq}'
- seq:
- - a
- - b
+ - csit-view
- - project:
- name: project-stream2
- project: project
- project-name: project
- jobs:
- - '{project-name}-{seq}'
- seq:
- - x
- - y
+ view-name: CSIT-1node
+ view-regex: '.*-csit-1node-.*'
- - job-template:
- name: '{project-name}-{seq}'
+upgrade:
+ - |
+ Some LF projects are already using a ``common-view`` template in their
+ local ci-management repo. This ``common-view`` is called ``project-view``
+ in global-jjb so rename all instances of ``common-view`` to
+ ``project-view`` when upgrading and remove the local ``common-view``
+ view-template definition from ci-management.
--- /dev/null
+---
+other:
+ - |
+ lftools' ``openstack`` module will now be installed as part of
+ pre-build.
--- /dev/null
+---
+features:
+ - |
+ The **openstack-cron** job now has the ability to remove images older than
+ a specified age (default: 30).
--- /dev/null
+---
+features:
+ - |
+ The **openstack-cron** job now has the ability to remove orphaned
+ servers.
--- /dev/null
+---
+features:
+ - |
+ The **openstack-cron** job now has the ability to remove orphaned
+ stacks.
+upgrade:
+ - |
+ The **openstack-cron** job now requires a new parameter configured
+ ``jenkins-urls`` in order to use the job.
+other:
+ - |
+ The **openstack-cron** job now runs every hour instead of daily. This is
+ because stack cleanup should happen more regularly.
--- /dev/null
+---
+features:
+ - |
+ The **openstack-cron** job now has the ability to remove orphaned
+ volumes.
--- /dev/null
+#!/bin/bash -l
+# SPDX-License-Identifier: EPL-1.0
+##############################################################################
+# Copyright (c) 2018 The Linux Foundation and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+##############################################################################
+echo "---> jenkins-verify-images.sh"
+# Verifies that openstack contains an image for each config file defined in the
+# jenkins-config/clouds/openstack directory.
+
+error=false
+
+for file in jenkins-config/clouds/openstack/*/*; do
+ # Set the $IMAGE_NAME variable to the the file's IMAGE_NAME value
+ export "$(grep IMAGE_NAME $file)"
+ # The image should be listed as active
+ openstack image list --property name="$IMAGE_NAME" | grep "active"
+ if [ $? -ne 0 ]; then
+ echo "ERROR: No matching image found for $IMAGE_NAME"
+ error=true
+ fi
+done
+
+if [ "$error" = true ]; then
+ exit 1
+fi
-#!/bin/bash
+#!/bin/bash -l
# SPDX-License-Identifier: EPL-1.0
##############################################################################
-# Copyright (c) 2018 The Linux Foundation and others.
+# Copyright (c) 2017, 2018 The Linux Foundation and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html
##############################################################################
-# Install the openstack cli
-echo "---> Install openstack cli"
+# Removes openstack images older than X days in the cloud
+echo "---> Cleanup old images"
+
+os_cloud="${OS_CLOUD:-vex}"
+os_image_cleanup_age="${OS_IMAGE_CLEANUP_AGE:-30}"
set -eux -o pipefail
-pip install --user --quiet --upgrade "pip<10.0.0" setuptools
-pip install --user --quiet --upgrade python-openstackclient python-heatclient
-pip freeze
+lftools openstack --os-cloud "${os_cloud}" image cleanup --days="${os_image_cleanup_age}"
--- /dev/null
+#!/bin/bash -l
+# SPDX-License-Identifier: EPL-1.0
+##############################################################################
+# Copyright (c) 2017, 2018 The Linux Foundation and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+##############################################################################
+# Scans OpenStack for orphaned servers
+echo "---> Orphaned servers"
+
+os_cloud="${OS_CLOUD:-vex}"
+jenkins_urls="${JENKINS_URLS:-}"
+
+minion_in_jenkins() {
+ # Usage: minion_in_jenkins STACK_NAME JENKINS_URL [JENKINS_URL...]
+ # Returns: 0 If stack is in Jenkins and 1 if stack is not in Jenkins.
+
+ MINION="${1}"
+
+ minions=()
+ for jenkins in "${@:2}"; do
+ JENKINS_URL="$jenkins/computer/api/json?tree=computer[displayName]"
+ resp=$(curl -s -w "\\n\\n%{http_code}" --globoff -H "Content-Type:application/json" "$JENKINS_URL")
+ json_data=$(echo "$resp" | head -n1)
+ status=$(echo "$resp" | awk 'END {print $NF}')
+
+ if [ "$status" != 200 ]; then
+ >&2 echo "ERROR: Failed to fetch data from $JENKINS_URL with status code $status"
+ >&2 echo "$resp"
+ exit 1
+ fi
+
+ # We purposely want to wordsplit here to combine the arrays
+ # shellcheck disable=SC2206,SC2207
+ minions=(${minions[@]} $(echo "$json_data" | \
+ jq -r '.computer[].displayName' | grep -v master)
+ )
+ done
+
+ if [[ "${minions[*]}" =~ $MINION ]]; then
+ return 0
+ fi
+
+ return 1
+}
+
+##########################
+## FETCH ACTIVE MINIONS ##
+##########################
+# Fetch server list before fetching active minions to minimize race condition
+# where we might be trying to delete servers while jobs are trying to start
+
+mapfile -t OS_SERVERS < <(openstack --os-cloud "$os_cloud" server list -f value -c "Name" | grep -E 'prd|snd')
+
+echo "-----> Active servers"
+for server in "${OS_SERVERS[@]}"; do
+ echo "$server"
+done
+
+
+#############################
+## DELETE ORPHANED SERVERS ##
+#############################
+echo "-----> Delete orphaned servers"
+
+# Search for servers not in use by any active Jenkins systems and remove them.
+for server in "${OS_SERVERS[@]}"; do
+ # jenkins_urls intentially needs globbing to be passed a separate params.
+ # needs to be globbed.
+ # shellcheck disable=SC2153,SC2086
+ if minion_in_jenkins "$server" $jenkins_urls; then
+ # No need to delete server if it is still attached to Jenkins
+ continue
+ else
+ echo "Deleting orphaned server: $server"
+ lftools openstack --os-cloud "$os_cloud" \
+ server remove --minutes 15 "$server"
+ fi
+done
--- /dev/null
+#!/bin/bash -l
+# SPDX-License-Identifier: EPL-1.0
+##############################################################################
+# Copyright (c) 2017, 2018 The Linux Foundation and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+##############################################################################
+# Scans OpenStack for orphaned stacks
+echo "---> Orphaned stacks"
+
+os_cloud="${OS_CLOUD:-vex}"
+jenkins_urls="${JENKINS_URLS:-}"
+
+stack_in_jenkins() {
+ # Usage: check_stack_in_jenkins STACK_NAME JENKINS_URL [JENKINS_URL...]
+ # Returns: 0 If stack is in Jenkins and 1 if stack is not in Jenkins.
+
+ STACK_NAME="${1}"
+
+ builds=()
+ for jenkins in "${@:2}"; do
+ JENKINS_URL="$jenkins/computer/api/json?tree=computer[executors[currentExecutable[url]],oneOffExecutors[currentExecutable[url]]]&xpath=//url&wrapper=builds"
+ resp=$(curl -s -w "\\n\\n%{http_code}" --globoff -H "Content-Type:application/json" "$JENKINS_URL")
+ json_data=$(echo "$resp" | head -n1)
+ #status=$(echo "$resp" | awk 'END {print $NF}')
+
+ if [[ "${jenkins}" == *"jenkins."*".org" ]] || [[ "${jenkins}" == *"jenkins."*".io" ]]; then
+ silo="production"
+ else
+ silo=$(echo "$jenkins" | sed 's/\/*$//' | awk -F'/' '{print $NF}')
+ fi
+ export silo
+ # We purposely want to wordsplit here to combine the arrays
+ # shellcheck disable=SC2206,SC2207
+ builds=(${builds[@]} $(echo "$json_data" | \
+ jq -r '.computer[].executors[].currentExecutable.url' \
+ | grep -v null | awk -F'/' '{print ENVIRON["silo"] "-" $6 "-" $7}')
+ )
+ done
+
+ if [[ "${builds[*]}" =~ $STACK_NAME ]]; then
+ return 0
+ fi
+
+ return 1
+}
+
+#########################
+## FETCH ACTIVE BUILDS ##
+#########################
+# Fetch stack list before fetching active builds to minimize race condition
+# where we might be try to delete stacks while jobs are trying to start
+
+mapfile -t OS_STACKS < <(openstack --os-cloud "$os_cloud" stack list \
+ -f value -c "Stack Name" -c "Stack Status" \
+ --property "stack_status=CREATE_COMPLETE" \
+ --property "stack_status=DELETE_FAILED" \
+ --property "stack_status=CREATE_FAILED" \
+ | awk '{print $1}')
+
+echo "-----> Active stacks"
+for stack in "${OS_STACKS[@]}"; do
+ echo "$stack"
+done
+
+
+##########################
+## DELETE UNUSED STACKS ##
+##########################
+echo "-----> Delete orphaned stacks"
+
+# Search for stacks not in use by any active Jenkins systems and remove them.
+for STACK_NAME in "${OS_STACKS[@]}"; do
+ # jenkins_urls intentially needs globbing to be passed a separate params.
+ # shellcheck disable=SC2153,SC2086
+ if stack_in_jenkins "$STACK_NAME" $jenkins_urls; then
+ # No need to delete stacks if there exists an active build for them
+ continue
+ else
+ echo "Deleting orphaned stack: $STACK_NAME"
+ lftools openstack --os-cloud "$os_cloud" stack delete "$STACK_NAME"
+ fi
+done
--- /dev/null
+#!/bin/bash -l
+# SPDX-License-Identifier: EPL-1.0
+##############################################################################
+# Copyright (c) 2018 The Linux Foundation and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+##############################################################################
+# Scans OpenStack for orphaned volumes
+echo "---> Orphaned volumes"
+
+os_cloud="${OS_CLOUD:-vex}"
+
+set -eux -o pipefail
+
+mapfile -t os_volumes < <(openstack --os-cloud "$os_cloud" volume list -f value -c ID --status Available)
+
+if [ ${#os_volumes[@]} -eq 0 ]; then
+ echo "No orphaned volumes found."
+else
+ for volume in "${os_volumes[@]}"; do
+ echo "Removing volume $volume"
+ lftools openstack --os-cloud "$os_cloud" volume remove --minutes 15 "$volume"
+ done
+fi
REQUIREMENTS_FILE=$(mktemp /tmp/requirements-XXXX.txt)
cat << EOF > "$REQUIREMENTS_FILE"
-lftools~=0.18.0
+lftools[openstack]~=0.18.0
python-heatclient~=1.16.1
python-openstackclient~=3.16.0
EOF