7 for (( index
=${#CLEANUP[@]}-1 ; index
>= 0 ; index--
)) ;do
16 REASON
="${2:-Unknown reason}"
22 trap cleanup EXIT TERM INT
29 ARCH
# The image architecture
30 IMAGE_TYPE
# The image type to create
31 VARIANT
# The variant of the base image to use
32 PROFILE
# The ansible group to apply to the new image
33 GIT_BRANCH
# The git branch of the automation repo to checkout
34 GIT_URL
# The git URL of the automation repo to checkout
35 LXD_CLIENT_CERT
# Path to LXD client certificate
36 LXD_CLIENT_KEY
# Path to LXD client certificate key
37 SSH_PRIVATE_KEY
# Path to SSH private key
38 TEST
# 'true' to test launching published image
41 for var
in "${REQUIRED_VARIABLES[@]}" ; do
42 if [ ! -v "$var" ] ; then
44 echo "Missing required variable: '${var}'" >&2
47 if [[ ! "${MISSING_VARS}" == "0" ]] ; then
48 fail
1 "Missing required variables"
51 # Default optional variables
52 INSTANCE_START_TIMEOUT
="${INSTANCE_START_TIMEOUT:-60}"
53 NETWORK_SLEEP
="${NETWORK_SLEEP:-15}"
56 apt-get
-y install lxd-client ansible jq
59 mkdir
-p ~
/.config
/lxc
60 cp "${LXD_CLIENT_CERT}" ~
/.config
/lxc
/client.crt
61 cp "${LXD_CLIENT_KEY}" ~
/.config
/lxc
/client.key
63 "rm -f ${HOME}/.config/lxc/client.crt"
64 "rm -f ${HOME}/.config/lxc/client.key"
66 lxc remote add ci
--accept-certificate --auth-type tls
"${LXD_HOST}"
70 git clone
-b "${GIT_BRANCH}" "${GIT_URL}" ci
71 cd ci
/automation
/ansible ||
exit 1
73 SOURCE_IMAGE_NAME
="${OS}/${RELEASE}/${VARIANT}/${ARCH}"
74 # Include IMAGE_TYPE since an alias may only be defined once even if the
75 # type of the image differs
76 TARGET_IMAGE_NAME
="${OS}/${RELEASE}/${VARIANT}/${ARCH}/${PROFILE}/${IMAGE_TYPE}"
78 # Try from local cache
80 if [ "${IMAGE_TYPE}" == "vm" ] ; then
86 # It's possible that concurrent image creation when running parallel jobs causes
87 # an error during the launch:
88 # Error: Failed instance creation: UNIQUE constraint failed: images.project_id, images.fingerprint
89 # C.f. https://github.com/canonical/lxd/issues/11636
93 while [[ "${TRIES}" -lt "${TRIES_MAX}" ]] ; do
94 if ! INSTANCE_NAME
=$
(lxc
-q launch
-e "${VM_ARG[@]}" -p default -p "${LXD_INSTANCE_PROFILE}" "${SOURCE_IMAGE_NAME}/${IMAGE_TYPE}") ; then
96 if ! INSTANCE_NAME
=$
(lxc
-q launch
-e "${VM_ARG[@]}" -p default -p "${LXD_INSTANCE_PROFILE}" images:"${SOURCE_IMAGE_NAME}") ; then
98 echo "Failed to deployed ephemereal instance attempt ${TRIES}/${TRIES_MAX}"
99 if [[ "${TRIES}" -lt "${TRIES_MAX}" ]] ; then
102 fail
1 "Failed to deploy ephemereal instance"
110 INSTANCE_NAME
="$(echo "${INSTANCE_NAME}" | cut -d ':' -f 2 | tr -d ' ')"
114 "lxc stop ${INSTANCE_NAME}"
117 # VMs may take more time to start, wait until instance is running
118 TIME_REMAINING
="${INSTANCE_START_TIMEOUT}"
121 INSTANCE_STATUS
=$
(lxc
exec "${INSTANCE_NAME}" hostname
)
123 if [[ "${INSTANCE_STATUS}" == "${INSTANCE_NAME}" ]] ; then
127 TIME_REMAINING
=$
((TIME_REMAINING
- 1))
128 if [ "${TIME_REMAINING}" -lt "0" ] ; then
129 fail
1 "Timed out waiting for instance to become available via 'lxc exec'"
133 # Wait for cloud-init to finish
134 if [[ "${VARIANT}" == "cloud" ]] ; then
135 # It's possible for cloud-init to fail, but to still be able to continue.
136 # Eg., a profile asks for netplan.io on a system that doesn't have that
138 lxc
exec "${INSTANCE_NAME}" -- cloud-init status
-w || true
141 # Wait for instance to have an ip address (@TODO: is there a better approach?)
142 sleep "${NETWORK_SLEEP}"
144 # @TODO: Handle case when iputils2 is not installed
146 POTENTIAL_INTERFACES
=(eth0 enp5s0
)
147 lxc
exec "${INSTANCE_NAME}" -- ip a
149 for interface
in "${POTENTIAL_INTERFACES[@]}" ; do
150 if ! DEV_INFO
="$(lxc exec "${INSTANCE_NAME}" -- ip a show dev "${interface}")" ; then
153 INSTANCE_IP
="$(echo "${DEV_INFO}" | grep -Eo 'inet [^ ]* ' | cut -d' ' -f2 | cut -d'/' -f1)"
154 if [[ "${INSTANCE_IP}" != "" ]] ; then
159 if [[ "${INSTANCE_IP}" == "" ]] ; then
160 fail
1 "Failed to determine instance IP address"
163 ssh-keyscan
"${INSTANCE_IP}" >> ~
/.ssh
/known_hosts2
164 #lxc exec "${INSTANCE_NAME}" -- bash -c 'for i in /etc/ssh/ssh_host_*_key ; do ssh-keygen -l -f "$i" ; done' >> "${HOME}/.ssh/known_hosts"
166 "rm -f ${HOME}/.ssh/known_hosts2"
168 cp "${SSH_PRIVATE_KEY}" ~
/.ssh
/id_rsa
169 ssh-keygen
-f ~
/.ssh
/id_rsa
-y > ~
/.ssh
/id_rsa.pub
171 "rm -f ${HOME}/.ssh/id_rsa.pub"
172 "rm -f ${HOME}/.ssh/id_rsa"
174 lxc
file push ~
/.ssh
/id_rsa.pub
"ci:${INSTANCE_NAME}/root/.ssh/authorized_keys2"
176 # Confirm working SSH connection
177 if ! ssh "${INSTANCE_IP}" hostname
; then
178 fail
1 "Unable to reach ephemereal instance over SSH"
182 cat > fake-inventory
<<EOF
187 "rm -f $(pwd)/fake-inventory"
190 LANG
=C ANSIBLE_STRATEGY
=linear ansible-playbook site.yml \
191 -e '{"compilers_legacy_install": false, "jenkins_user": false, "lttng_modules_checkout_repo": false}' \
192 -l "${INSTANCE_IP}" -i fake-inventory
194 # Cleanup instance side
195 LANG
=C ANSIBLE_STRATEGY
=linear ansible-playbook \
196 playbooks
/post-imagebuild-clean.yml \
197 -l "${INSTANCE_IP}" -i fake-inventory
200 lxc publish
"${INSTANCE_NAME}" --alias "${TARGET_IMAGE_NAME}" -f
204 if [[ "${TEST}" == "true" ]] ; then
206 while [[ "${TRIES}" -lt "${TRIES_MAX}" ]] ; do
207 if ! INSTANCE_NAME
=$
(lxc
-q launch
-e "${VM_ARG[@]}" -p default -p "${LXD_INSTANCE_PROFILE}" "${TARGET_IMAGE_NAME}") ; then
209 echo "Failed to launch instance try ${TRIES}/${TRIES_MAX}"
210 if [[ "${TRIES}" -lt "${TRIES_MAX}" ]] ; then
211 sleep $
((1 + RANDOM
% 10))
214 fail
1 "Failed to launch an instance using newly published image '${TARGET_IMAGE_NAME}'"
216 INSTANCE_NAME
="$(echo "${INSTANCE_NAME}" | cut -d':' -f2 | tr -d ' ')"
218 "lxc stop -f ${INSTANCE_NAME}"