Retire repository

Fuel repositories are all retired in openstack namespace, retire
remaining fuel repos in x namespace since they are unused now.

This change removes all content from the repository and adds the usual
README file to point out that the repository is retired following the
process from
https://docs.openstack.org/infra/manual/drivers.html#retiring-a-project

See also
http://lists.openstack.org/pipermail/openstack-discuss/2019-December/011675.html

A related change is: https://review.opendev.org/699752 .

Change-Id: I08b13994e5611b2baf804e3dc517fd9b74b83b57
This commit is contained in:
Andreas Jaeger 2019-12-18 19:38:59 +01:00
parent 67b9985b92
commit f98ab6d7c1
115 changed files with 10 additions and 7371 deletions

3
.gitignore vendored
View File

@ -1,3 +0,0 @@
.build
repositories/ubuntu/*.deb
fuel-plugin-ironic*.rpm

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "deployment_scripts/puppet/modules/tftp"]
path = deployment_scripts/puppet/modules/tftp
url = https://github.com/puppetlabs/puppetlabs-tftp

202
LICENSE
View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,4 +0,0 @@
fuel-plugin-ironic
============
Plugin description

10
README.rst Normal file
View File

@ -0,0 +1,10 @@
This project is no longer maintained.
The contents of this repository are still available in the Git
source code management system. To see the contents of this
repository before it reached its end of life, please check out the
previous commit with "git checkout HEAD^1".
For any further questions, please email
openstack-discuss@lists.openstack.org or join #openstack-dev on
Freenode.

View File

@ -1,52 +0,0 @@
VERSION?=8.0.0
top_srcdir:=$(shell pwd)
ubuntu_DATA:=$(shell cd $(top_srcdir) && find share -type f)
top_builddir?=$(shell pwd)
-include config.mk
PREFIX?=/usr
all:
@echo nop
install:
install -d -m 755 $(DESTDIR)$(PREFIX)/bin
install -d -m 755 $(DESTDIR)$(PREFIX)/share/fuel-bootstrap-image
install -m 755 -t $(DESTDIR)$(PREFIX)/bin $(top_srcdir)/bin/fuel-bootstrap-image
install -m 755 -t $(DESTDIR)$(PREFIX)/bin $(top_srcdir)/bin/fuel-bootstrap-image-set
tar cf - -C $(top_srcdir) share | tar xf - -C $(DESTDIR)$(PREFIX)
dist: $(top_builddir)/fuel-bootstrap-image-builder-$(VERSION).tar.gz
$(top_builddir)/fuel-bootstrap-image-builder-$(VERSION).tar.gz: STAGEDIR:=$(top_builddir)/dist/fuel-bootstrap-image-builder
$(top_builddir)/fuel-bootstrap-image-builder-$(VERSION).tar.gz: bin/fuel-bootstrap-image $(ubuntu_DATA) Makefile configure
mkdir -p $(STAGEDIR)/share
mkdir -p $(STAGEDIR)/bin
tar cf - -C $(top_srcdir) bin share | tar xf - -C $(STAGEDIR)
cp -a $(top_srcdir)/Makefile $(top_srcdir)/configure $(top_srcdir)/fuel-bootstrap-image-builder.spec $(STAGEDIR)
tar czf $@.tmp -C $(dir $(STAGEDIR)) $(notdir $(STAGEDIR))
mv $@.tmp $@
rpm: SANDBOX:=$(top_builddir)/rpmbuild
rpm: $(top_builddir)/fuel-bootstrap-image-builder-$(VERSION).tar.gz fuel-bootstrap-image-builder.spec
rm -rf $(SANDBOX)
mkdir -p $(SANDBOX)/SOURCES $(SANDBOX)/SPECS $(SANDBOX)/tmp
cp -a $< $(SANDBOX)/SOURCES
cp -a $(top_srcdir)/fuel-bootstrap-image-builder.spec $(SANDBOX)/SPECS
fakeroot rpmbuild --nodeps \
--define '_tmppath $(SANDBOX)/tmp' \
--define '_topdir $(SANDBOX)' \
--define 'version $(VERSION)' \
-ba $(SANDBOX)/SPECS/fuel-bootstrap-image-builder.spec
clean:
-@rm -f $(top_builddir)/config.mk
distclean: clean
-@rm -f $(top_builddir)/fuel-bootstrap-image-builder-$(VERSION).tar.gz
-@rm -rf $(top_builddir)/rpmbuild
-@rm -rf $(top_builddir)/dist
.PHONY: all install dist clean rpm

View File

@ -1,467 +0,0 @@
#!/bin/sh
set -ex
MYSELF="${0##*/}"
bindir="${0%/*}"
datadir="${bindir%/*}/share/fuel-bootstrap-image"
global_conf="/etc/fuel-bootstrap-image.conf"
[ -r "$global_conf" ] && . "$global_conf"
[ -z "$MOS_VERSION" ] && MOS_VERSION="8.0"
[ -z "$DISTRO_RELEASE" ] && DISTRO_RELEASE="trusty"
[ -z "$MIRROR_DISTRO" ] && MIRROR_DISTRO="http://archive.ubuntu.com/ubuntu"
[ -z "$MIRROR_MOS" ] && MIRROR_MOS="http://mirror.fuel-infra.org/mos-repos/ubuntu/$MOS_VERSION"
[ -z "$KERNEL_FLAVOR" ] && KERNEL_FLAVOR="-generic-lts-trusty"
[ -z "$ARCH" ] && ARCH="amd64"
[ -z "$DESTDIR" ] && DESTDIR="/var/www/nailgun/bootstrap/ubuntu"
# Packages required for the master node to discover a bootstrap node
BOOTSTRAP_FUEL_PKGS_DFLT="openssh-client openssh-server ntp mcollective nailgun-agent nailgun-mcagents nailgun-net-check fuel-agent"
[ -z "$BOOTSTRAP_FUEL_PKGS" ] && BOOTSTRAP_FUEL_PKGS="$BOOTSTRAP_FUEL_PKGS_DFLT"
if [ -z "$BOOTSTRAP_IRONIC" ]; then
GONFIG_SOURCE="$datadir/ubuntu/files/"
else
GONFIG_SOURCE="$datadir/ubuntu/files.ironic/"
fi
if [ -n "$http_proxy" ]; then
export HTTP_PROXY="$http_proxy"
elif [ -n "$HTTP_PROXY" ]; then
export http_proxy="$HTTP_PROXY"
fi
# Kernel, firmware, live boot
BOOTSTRAP_PKGS="ubuntu-minimal live-boot live-boot-initramfs-tools linux-image${KERNEL_FLAVOR} linux-firmware linux-firmware-nonfree"
# compress initramfs with xz, make squashfs root filesystem image
BOOTSTRAP_PKGS="$BOOTSTRAP_PKGS xz-utils squashfs-tools"
# Smaller tools providing the standard ones.
# - mdadm depends on mail-transport-agent, default one is postfix => use msmtp instead
BOOTSTRAP_PKGS="$BOOTSTRAP_PKGS msmtp-mta gdebi-core"
apt_setup ()
{
local root="$1"
local sources_list="${root}/etc/apt/sources.list"
local apt_prefs="${root}/etc/apt/preferences"
local mos_codename="mos${MOS_VERSION}"
local release_file="$MIRROR_MOS/dists/$mos_codename/Release"
if ! wget -q -O /dev/null "$release_file" 2>/dev/null; then
cat >&2 <<-EOF
$MYSELF: broken MOS repo: no $release_file"
EOF
exit 2
fi
mkdir -p "${sources_list%/*}"
cat > "$sources_list" <<-EOF
deb $MIRROR_DISTRO ${DISTRO_RELEASE} main universe multiverse restricted
deb $MIRROR_DISTRO ${DISTRO_RELEASE}-security main universe multiverse restricted
deb $MIRROR_DISTRO ${DISTRO_RELEASE}-updates main universe multiverse restricted
deb $MIRROR_MOS ${mos_codename} main
deb $MIRROR_MOS ${mos_codename}-security main
deb $MIRROR_MOS ${mos_codename}-updates main
deb $MIRROR_MOS ${mos_codename}-holdback main
EOF
if [ -n "$EXTRA_DEB_REPOS" ]; then
l="$EXTRA_DEB_REPOS"
IFS='|'
set -- $l
unset IFS
for repo; do
echo "$repo"
done >> "$sources_list"
fi
cat > "$apt_prefs" <<-EOF
Package: *
Pin: release o=Mirantis, n=mos${MOS_VERSION}
Pin-Priority: 1101
Package: *
Pin: release o=Mirantis, n=${DISTRO_RELEASE}
Pin-Priority: 1101
EOF
if [ -n "$HTTP_PROXY" ]; then
cat > "$root/etc/apt/apt.conf.d/01mirantis-use-proxy" <<-EOF
Acquire::http::Proxy "$HTTP_PROXY";
EOF
fi
}
run_apt_get ()
{
local root="$1"
shift
chroot "$root" env \
LC_ALL=C \
DEBIAN_FRONTEND=noninteractive \
DEBCONF_NONINTERACTIVE_SEEN=true \
TMPDIR=/tmp \
TMP=/tmp \
apt-get $@
}
run_apt_key ()
{
local root="$1"
shift
chroot "$root" env \
LC_ALL=C \
DEBIAN_FRONTEND=noninteractive \
DEBCONF_NONINTERACTIVE_SEEN=true \
TMPDIR=/tmp \
TMP=/tmp \
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys $@
}
dpkg_is_too_old ()
{
# XXX: dpkg-deb versions older than 1.15.6 can't handle data.tar.xz
# (which is the default payload of Ubuntu packages)
# Such an ancient version of dpkg is shipped with CentOS 6.[56]
local dpkg_version
local dpkg_major_version
local dpkg_minor_version
local dpkg_patch_version
if ! dpkg-deb --help >/dev/null 2>&1; then
return 0
fi
dpkg_version=`dpkg-deb --version | sed -rne '1 s/^.*\s+version\s+([0-9]+)\.([0-9]+)\.([0-9]+).*/\1.\2.\3/p'`
[ -z "$dpkg_version" ] && return 0
IFS='.'
set -- $dpkg_version
unset IFS
dpkg_major_version="$1"
dpkg_minor_version="$2"
dpkg_patch_version="$3"
if [ $dpkg_major_version -le 1 ] && [ $dpkg_minor_version -le 15 ] && [ $dpkg_patch_version -lt 6 ]; then
echo "DEBUG: $MYSELF: dpkg is too old, using ar to unpack debian packages" >&2
return 0
fi
return 1
}
run_debootstrap ()
{
local root="$1"
[ -z "$root" ] && exit 1
local insecure="--no-check-gpg"
local extractor=''
if dpkg_is_too_old; then
# Ubuntu packages use data.tar.xz payload. Ancient versions of
# dpkg (in particular the ones shipped with CentOS 6.x) can't
# handle such packages. Tell debootstrap to use ar instead to
# avoid the failure.
extractor='--extractor=ar'
fi
env \
LC_ALL=C \
DEBIAN_FRONTEND=noninteractive \
DEBCONF_NONINTERACTIVE_SEEN=true \
debootstrap $insecure $extractor --arch=${ARCH} ${DISTRO_RELEASE} "$root" $MIRROR_DISTRO
}
install_packages ()
{
local root="$1"
shift
echo "INFO: $MYSELF: installing pkgs: $*" >&2
run_apt_get "$root" install --yes $@
}
upgrade_chroot ()
{
local root="$1"
run_apt_key "$root" CA2B20483E301371
run_apt_get "$root" update
if ! mountpoint -q "$root/proc"; then
mount -t proc bootstrapproc "$root/proc"
fi
run_apt_get "$root" dist-upgrade --yes
}
add_local_mos_repo ()
{
# we need the local APT repo (/var/www/nailgun/ubuntu/x86_64)
# before web server is up and running => use bind mount
local root="$1"
# TODO(asheplyakov): use proper arch name (amd64)
local local_repo="/var/www/nailgun/ubuntu/x86_64"
local path_in_chroot="/tmp/local-apt"
local source_parts_d="${root}/etc/apt/sources.list.d"
# TODO(asheplyakov): update the codename after repo get fixed
local mos_codename="mos${MOS_VERSION}"
mkdir -p "${root}${path_in_chroot}" "${source_parts_d}"
mount -o bind "$local_repo" "${root}${path_in_chroot}"
mount -o remount,ro,bind "${root}${path_in_chroot}"
cat > "${source_parts_d}/nailgun-local.list" <<-EOF
deb file://${path_in_chroot} ${mos_codename} main
EOF
}
allow_insecure_apt ()
{
local root="$1"
local conflet="${root}/etc/apt/apt.conf.d/02mirantis-insecure-apt"
mkdir -p "${conflet%/*}"
echo 'APT::Get::AllowUnauthenticated 1;' > "$conflet"
}
suppress_services_start ()
{
local root="$1"
local policy_rc="$root/usr/sbin/policy-rc.d"
mkdir -p "${policy_rc%/*}"
cat > "$policy_rc" <<-EOF
#!/bin/sh
# suppress services start in the staging chroot
exit 101
EOF
chmod 755 "$policy_rc"
}
propagate_host_resolv_conf ()
{
local root="$1"
mkdir -p "$root/etc"
for conf in "/etc/resolv.conf" "/etc/hosts"; do
if [ -e "${root}${conf}" ]; then
cp -a "${root}${conf}" "${root}${conf}.bak"
fi
done
}
restore_resolv_conf ()
{
local root="$1"
for conf in "/etc/resolv.conf" "/etc/hosts"; do
if [ -e "${root}${conf}.bak" ]; then
rm -f "${root}${conf}"
cp -a "${root}${conf}.bak" "${root}${conf}"
fi
done
}
make_utf8_locale ()
{
local root="$1"
chroot "$root" /bin/sh -c "locale-gen en_US.UTF-8 && dpkg-reconfigure locales"
}
# XXX: CentOS version of debootstrap produces a broken /dev:
# /dev/fd is a directory instead of a symlink to /proc/self/fd
dev_fixup ()
{
local root="$1"
if [ -z "$root" ]; then
echo "*** Error: $MYSELF: dev_fixup: \$root is not specified" >&2
exit 1
fi
mkdir -p -m755 "$root/dev"
if [ ! -L "$root/dev/fd" ]; then
rm -rf "$root/dev/fd"
# Ask MAKEDEV to re-create /dev/fd, /dev/stdin, etc
chroot "$root" /bin/sh -c "cd /dev && MAKEDEV fd"
fi
if [ ! -c "$root/dev/null" ]; then
# basic device nodes are missing => create them
chroot "$root" /bin/sh -c "cd /dev && MAKEDEV std"
fi
}
copy_conf_files ()
{
local root="$1"
local sdir="$2"
rsync -rlptDK "${sdir}" "${root%/}"
sed -i $root/etc/shadow -e '/^root/c\root:$6$oC7haQNQ$LtVf6AI.QKn9Jb89r83PtQN9fBqpHT9bAFLzy.YVxTLiFgsoqlPY3awKvbuSgtxYHx4RUcpUqMotp.WZ0Hwoj.:15441:0:99999:7:::'
}
install_ssh_keys ()
{
local root="$1"
shift
if [ -z "$*" ]; then
echo "*** Error: $MYSELF: no ssh keys specified" >&2
exit 1
fi
local authorized_keys="$root/root/.ssh/authorized_keys"
local dot_ssh_dir="${authorized_keys%/*}"
if [ ! -d "${dot_ssh_dir}" ]; then
mkdir -p -m700 "${dot_ssh_dir}"
fi
for key; do
if [ ! -r "$key" ]; then
echo "*** Error: $MYSELF: no such file: $key" >&2
exit 1
fi
done
cat $@ > "$authorized_keys"
chmod 640 "$authorized_keys"
}
cleanup_chroot ()
{
local root="$1"
[ -z "$root" ] && exit 1
signal_chrooted_processes "$root" SIGTERM
signal_chrooted_processes "$root" SIGKILL
# umount "${root}/tmp/local-apt" 2>/dev/null || umount -l "${root}/tmp/local-apt"
# rm -f "${root}/etc/apt/sources.list.d/nailgun-local.list"
rm -rf $root/var/cache/apt/archives/*.deb
rm -f $root/etc/apt/apt.conf.d/01mirantis-use-proxy.conf
rm -f $root/var/log/bootstrap.log
rm -rf $root/tmp/*
rm -rf $root/run/*
}
install_agent ()
{
local root="$1"
local package_path="$2"
local full_path=`ls $package_path/fuel-agent*.deb`
local package=`basename $full_path`
cp $full_path $root/tmp
chroot "$root" env \
LC_ALL=C \
DEBIAN_FRONTEND=noninteractive \
DEBCONF_NONINTERACTIVE_SEEN=true \
TMPDIR=/tmp \
TMP=/tmp \
gdebi -n /tmp/$package
rm -f $root/tmp/$package
}
recompress_initramfs ()
{
local root="$1"
local initramfs_conf="$root/etc/initramfs-tools/initramfs.conf"
sed -i $initramfs_conf -re 's/COMPRESS\s*=\s*gzip/COMPRESS=xz/'
rm -f $root/boot/initrd*
chroot "$root" \
env \
LC_ALL=C \
DEBIAN_FRONTEND=noninteractive \
DEBCONF_NONINTERACTIVE_SEEN=true \
TMPDIR=/tmp \
TMP=/tmp \
update-initramfs -c -k all
}
mk_squashfs_image ()
{
local root="$1"
local tmp="$$"
[ -d "$DESTDIR" ] && mkdir -p "$DESTDIR"
cp -a $root/boot/initrd* $DESTDIR/initramfs.img.${tmp}
cp -a $root/boot/vmlinuz* $DESTDIR/linux.${tmp}
rm -f $root/boot/initrd*
rm -f $root/boot/vmlinuz*
# run mksquashfs inside a chroot (Ubuntu kernel will be able to
# mount an image produced by Ubuntu squashfs-tools)
mount -t tmpfs -o rw,nodev,nosuid,noatime,mode=0755,size=4M mnt${tmp} "$root/mnt"
mkdir -p "$root/mnt/src" "$root/mnt/dst"
mount -o bind "$root" "$root/mnt/src"
mount -o remount,bind,ro "$root/mnt/src"
mount -o bind "$DESTDIR" "$root/mnt/dst"
if ! mountpoint -q "$root/proc"; then
mount -t proc sandboxproc "$root/proc"
fi
chroot "$root" mksquashfs /mnt/src /mnt/dst/root.squashfs.${tmp} -comp xz -no-progress -noappend
mv $DESTDIR/initramfs.img.${tmp} $DESTDIR/initramfs.img
mv $DESTDIR/linux.${tmp} $DESTDIR/linux
mv $DESTDIR/root.squashfs.${tmp} $DESTDIR/root.squashfs
umount "$root/mnt/dst"
umount "$root/mnt/src"
umount "$root/mnt"
}
build_image ()
{
local root="$1"
chmod 755 "$root"
suppress_services_start "$root"
run_debootstrap "$root"
dev_fixup "$root"
suppress_services_start "$root"
propagate_host_resolv_conf "$root"
make_utf8_locale "$root"
apt_setup "$root"
# add_local_mos_repo "$root"
allow_insecure_apt "$root"
upgrade_chroot "$root"
install_packages "$root" $BOOTSTRAP_PKGS $BOOTSTRAP_FUEL_PKGS
install_agent "$root" $AGENT_PACKAGE_PATH
recompress_initramfs "$root"
copy_conf_files "$root" $GONFIG_SOURCE
if [ -n "$BOOTSTRAP_SSH_KEYS" ]; then
install_ssh_keys "$root" $BOOTSTRAP_SSH_KEYS
else
cat >&2 <<-EOF
$MYSELF: Warning: no ssh keys specified
$MYSELF: bootstrap nodes won't be available via ssh
EOF
fi
restore_resolv_conf "$root"
cleanup_chroot "$root"
mk_squashfs_image "$root"
}
root=`mktemp -d --tmpdir fuel-bootstrap-image.XXXXXXXXX`
main ()
{
build_image "$root"
}
signal_chrooted_processes ()
{
local root="$1"
local signal="${2:-SIGTERM}"
local max_attempts=10
local timeout=2
local count=0
local found_processes
[ ! -d "$root" ] && return 0
while [ $count -lt $max_attempts ]; do
found_processes=''
for pid in `fuser $root 2>/dev/null`; do
[ "$pid" = "kernel" ] && continue
if [ "`readlink /proc/$pid/root`" = "$root" ]; then
found_processes='yes'
kill "-${signal}" $pid
fi
done
[ -z "$found_processes" ] && break
count=$((count+1))
sleep $timeout
done
}
final_cleanup ()
{
signal_chrooted_processes "$root" SIGTERM
signal_chrooted_processes "$root" SIGKILL
for mnt in /tmp/local-apt /mnt/dst /mnt/src /mnt /proc; do
if mountpoint -q "${root}${mnt}"; then
umount "${root}${mnt}" || umount -l "${root}${mnt}" || true
fi
done
if [ -z "$SAVE_TEMPS" ]; then
rm -rf "$root"
fi
}
trap final_cleanup 0
trap final_cleanup HUP TERM INT QUIT
main

View File

@ -1,120 +0,0 @@
#!/bin/sh
# Script for switching between the Ubuntu and CentOS based bootstrap images.
# Usage: fuel-bootstrap-image-set centos|ubuntu
set -e
MYSELF="${0##*/}"
ASTUTE_YAML="/etc/fuel/astute.yaml"
cobbler_manifest="/etc/puppet/modules/nailgun/examples/cobbler-only.pp"
astute_manifest="/etc/puppet/modules/nailgun/examples/astute-only.pp"
ubuntu_bootstrap_dir="/var/www/nailgun/bootstrap/ubuntu"
bootstrap_conf="/etc/fuel-bootstrap-image.conf"
run_puppet () {
local container="$1"
local manifest="$2"
local ret=''
set +e
dockerctl shell "$container" puppet apply --detailed-exitcodes -dv "$manifest"
ret=$?
set -e
if [ "$ret" = "0" ] || [ "$ret" = "2" ]; then
return 0
else
cat >&2 <<-EOF
$MYSELF: puppet apply $manifest failed: exit code $ret
$MYSELF: container: $container
EOF
exit 1
fi
}
maybe_build_ubuntu_bootstrap ()
{
local log='/var/log/fuel-bootstrap-image-build.log'
local need_rebuild=''
for item in linux initramfs.img root.squashfs; do
if [ ! -f "$ubuntu_bootstrap_dir/$item" ]; then
need_rebuild='yes'
fi
done
if ! grep -qE '^\s*BOOTSTRAP_SSH_KEYS\s*[=]' "$bootstrap_conf" 2>/dev/null; then
echo >> "$bootstrap_conf"
echo "BOOTSTRAP_SSH_KEYS=\"/root/.ssh/id_rsa.pub\"" >> "$bootstrap_conf"
fi
if [ -n "$need_rebuild" ]; then
cat >&2 <<-EOF
$MYSELF: info: Ubuntu bootstrap image does not exist, building one
$MYSELF: info: build log is available at $log
EOF
if ! fuel-bootstrap-image >>"$log" 2>&1; then
cat >&2 <<-EOF
$MYSELF: error: failed to build Ubuntu bootstrap image
$MYSELF: error: see $log for more details
EOF
exit 1
fi
fi
}
maybe_restart_dnsmasq () {
if ! dockerctl shell cobbler service dnsmasq status >/dev/null; then
dockerctl shell cobbler service dnsmasq restart
fi
}
verify_bootstrap_flavor () {
local flavor="$1"
if [ -z "$flavor" ]; then
cat >&2 <<-EOF
$MYSELF: error: no bootstrap image specified
Usage: $MYSELF centos|ubuntu
EOF
exit 1
fi
case "$flavor" in
centos|CentOS)
flavor='centos'
;;
ubuntu|Ubuntu)
flavor='ubuntu'
cat >&2 <<-EOF
$MYSELF: WARNING: Ubuntu based bootstrap is EXPERIMENTAL.
$MYSELF: WARNING: Use at your own risk.
EOF
;;
*)
cat >&2 <<-EOF
$MYSELF: error: unknown bootstrap image: $flavor
$MYSELF: available bootstrap images: ubuntu, centos
EOF
exit 1
;;
esac
}
write_astute_yaml () {
local flavor="$1"
python <<-PYEOF
from fuelmenu.fuelmenu import Settings
conf = Settings().read("$ASTUTE_YAML").get('BOOTSTRAP', {})
conf['flavor'] = "$flavor"
Settings().write({'BOOTSTRAP': conf}, outfn="$ASTUTE_YAML", defaultsfile=None)
PYEOF
}
switch_bootstrap () {
local flavor="$1"
verify_bootstrap_flavor "$flavor"
if [ "$flavor" = "ubuntu" ]; then
maybe_build_ubuntu_bootstrap
fi
write_astute_yaml "$flavor"
run_puppet cobbler "$cobbler_manifest"
# XXX: sometimes dnsmasq stops after cobbler sync
maybe_restart_dnsmasq
run_puppet astute "$astute_manifest"
# XXX: astute puppet manifest should take care to restart astuted on its own
dockerctl shell astute killall -sHUP supervisord
}
switch_bootstrap $1

View File

@ -1,21 +0,0 @@
#!/bin/sh
set -e
# Stub configure script to make rpmbuild happy
PREFIX=''
for arg; do
case $arg in
--prefix)
shift
PREFIX="$arg"
;;
--prefix=*)
PREFIX="${arg##--prefix=*}"
;;
esac
done
cat > config.mk <<-EOF
PREFIX:=${PREFIX:-/usr}
EOF

View File

@ -1,38 +0,0 @@
%define name fuel-bootstrap-image-builder
%{!?version: %define version 8.0.0}
%{!?release: %define release 1}
Summary: Fuel bootstrap image generator
Name: %{name}
Version: %{version}
Release: %{release}
URL: http://github.com/asheplyakov/fuel-bootstrap-image
Source0: fuel-bootstrap-image-builder-%{version}.tar.gz
License: Apache
BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
Prefix: %{_prefix}
Requires: debootstrap, wget
BuildArch: noarch
%description
Fuel bootstrap image generator package
%prep
%autosetup -n %{name}
%build
%configure
%install
%make_install
mkdir -p %{buildroot}/var/www/nailgun/bootstrap/ubuntu
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
%{_bindir}/*
%{_datadir}/fuel-bootstrap-image/*
%dir /var/www/nailgun/bootstrap/ubuntu

View File

@ -1,184 +0,0 @@
[DEFAULT]
#
# Options defined in fuel_agent.manager
#
# Data driver (string value)
#data_driver=nailgun
# Path to directory with cloud init templates (string value)
#nc_template_path=/usr/share/fuel-agent/cloud-init-templates
# Temporary directory for file manipulations (string value)
#tmp_path=/tmp
# Path where to store generated config drive image (string
# value)
#config_drive_path=/tmp/config-drive.img
# Path where to store actual rules for udev daemon (string
# value)
#udev_rules_dir=/etc/udev/rules.d
# Path where to store default rules for udev daemon (string
# value)
#udev_rules_lib_dir=/lib/udev/rules.d
# Substring to which file extension .rules be renamed (string
# value)
#udev_rename_substr=.renamedrule
# Directory where we build images (string value)
#image_build_dir=/tmp
# Directory where we build images (string value)
#image_build_suffix=.fuel-agent-image
#
# Options defined in fuel_agent.cmd.agent
#
# Input data file (string value)
#input_data_file=/tmp/provision.json
# Input data (json string) (string value)
#input_data=
#
# Options defined in fuel_agent.openstack.common.log
#
# Print debugging output (set logging level to DEBUG instead
# of default WARNING level). (boolean value)
#debug=true
# Print more verbose output (set logging level to INFO instead
# of default WARNING level). (boolean value)
#verbose=false
# Log output to standard error. (boolean value)
use_stderr=false
# Format string to use for log messages with context. (string
# value)
#logging_context_format_string=%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s
# Format string to use for log messages without context.
# (string value)
#logging_default_format_string=%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s
# Data to append to log format when level is DEBUG. (string
# value)
logging_debug_format_suffix=
# Prefix each line of exception output with this format.
# (string value)
#logging_exception_prefix=%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s
# List of logger=LEVEL pairs. (list value)
#default_log_levels=amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN
# Enables or disables publication of error events. (boolean
# value)
#publish_errors=false
# Enables or disables fatal status of deprecations. (boolean
# value)
#fatal_deprecations=false
# The format for an instance that is passed with the log
# message. (string value)
#instance_format="[instance: %(uuid)s] "
# The format for an instance UUID that is passed with the log
# message. (string value)
#instance_uuid_format="[instance: %(uuid)s] "
# The name of a logging configuration file. This file is
# appended to any existing logging configuration files. For
# details about logging configuration files, see the Python
# logging module documentation. (string value)
# Deprecated group/name - [DEFAULT]/log_config
#log_config_append=<None>
# DEPRECATED. A logging.Formatter log message format string
# which may use any of the available logging.LogRecord
# attributes. This option is deprecated. Please use
# logging_context_format_string and
# logging_default_format_string instead. (string value)
#log_format=<None>
# Format string for %%(asctime)s in log records. Default:
# %(default)s . (string value)
#log_date_format=%Y-%m-%d %H:%M:%S
# (Optional) Name of log file to output to. If no default is
# set, logging will go to stdout. (string value)
# Deprecated group/name - [DEFAULT]/logfile
log_file=/var/log/fuel-agent.log
# (Optional) The base directory used for relative --log-file
# paths. (string value)
# Deprecated group/name - [DEFAULT]/logdir
#log_dir=<None>
# Use syslog for logging. Existing syslog format is DEPRECATED
# during I, and will change in J to honor RFC5424. (boolean
# value)
use_syslog=true
# (Optional) Enables or disables syslog rfc5424 format for
# logging. If enabled, prefixes the MSG part of the syslog
# message with APP-NAME (RFC5424). The format without the APP-
# NAME is deprecated in I, and will be removed in J. (boolean
# value)
use_syslog_rfc_format=true
# Syslog facility to receive log lines. (string value)
#syslog_log_facility=LOG_USER
#
# Options defined in fuel_agent.utils.artifact
#
# Size of data chunk to operate with images (integer value)
#data_chunk_size=1048576
#
# Options defined in fuel_agent.utils.build
#
# Maximum allowed loop devices count to use (integer value)
#max_loop_count=255
# Size of sparse file in MiBs (integer value)
#sparse_file_size=2048
# System-wide major number for loop device (integer value)
#loop_dev_major=7
#
# Options defined in fuel_agent.utils.utils
#
# Maximum retries count for http requests. 0 means infinite
# (integer value)
#http_max_retries=30
# Http request timeout in seconds (floating point value)
#http_request_timeout=10.0
# Delay in seconds before the next http request retry
# (floating point value)
#http_retry_delay=2.0
# Block size of data to read for calculating checksum (integer
# value)
#read_chunk_size=1048576

View File

@ -1,10 +0,0 @@
description "Ironic call back script"
start on started ssh
pre-start script
/usr/bin/configure-remote-logging.sh
end script
task
exec /usr/bin/ironic_callback

View File

@ -1,29 +0,0 @@
#################
#### MODULES ####
#################
$ModLoad imuxsock # provides support for local system logging
$ModLoad imklog # provides kernel logging support (previously done by rklogd)
#$ModLoad immark # provides --MARK-- message capability
###########################
#### GLOBAL DIRECTIVES ####
###########################
#
# Set the default permissions for all log files.
#
$FileOwner syslog
$FileGroup syslog
$FileCreateMode 0640
$DirCreateMode 0755
$umask 0000
$PrivDropToUser syslog
$PrivDropToGroup syslog
$MaxMessageSize 32k
#
# Include all config files in /etc/rsyslog.d/
#
$IncludeConfig /etc/rsyslog.d/*.conf

View File

@ -1,36 +0,0 @@
# file is managed by puppet
#
# Log to remote syslog server
# Templates
# RFC3164 emulation with long tags (32+)
$Template RemoteLog, "<%pri%>%timestamp% ironic/@DEPLOYMENT_ID@/%syslogtag%%msg:::sp-if-no-1st-sp%%msg%\n"
# RFC544 emulation would be: "<%pri%>1 %timestamp:::date-rfc3339% %hostname% %syslogtag% %procid% %msgid% %structured-data% %msg%\n"
# Note: don't use %app-name% cuz it would be empty for some cases
$ActionFileDefaultTemplate RemoteLog
$WorkDirectory /var/spool/rsyslog/
#Start remote server 0
$ActionQueueType LinkedList # use asynchronous processing
$ActionQueueFileName remote0 # set file name, also enables disk mode
$ActionQueueMaxDiskSpace 1g
$ActionQueueSaveOnShutdown on
$ActionQueueLowWaterMark 2000
$ActionQueueHighWaterMark 8000
$ActionQueueSize 1000000 # Reserve 500Mb memory, each queue element is 512b
$ActionQueueDiscardMark 950000 # If the queue looks like filling, start discarding to not block ssh/login/etc.
$ActionQueueDiscardSeverity 0 # When in discarding mode discard everything.
$ActionQueueTimeoutEnqueue 0 # When in discarding mode do not enable throttling.
$ActionQueueDequeueSlowdown 1000
$ActionQueueWorkerThreads 2
$ActionQueueDequeueBatchSize 128
$ActionResumeRetryCount -1
# Isolate sudo logs locally
# match if "program name" is equal to "sudo"
:programname, isequal, "sudo" -/var/log/sudo.log
&~
# Send messages we receive to master node via tcp
# Use an octet-counted framing (understood for rsyslog only) to ensure correct multiline messages delivery
*.* @(o)@SYSLOG_SERVER_IP@:514;RemoteLog
#End remote server 0

View File

@ -1,20 +0,0 @@
Protocol 2
SyslogFacility AUTHPRIV
PasswordAuthentication no
PubkeyAuthentication yes
ChallengeResponseAuthentication no
GSSAPIAuthentication no
UsePAM no
UseDNS no
# Accept locale-related environment variables
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
AcceptEnv XMODIFIERS
Subsystem sftp /usr/lib/openssh/sftp-server
# Secure Ciphers and MACs
Ciphers aes256-ctr,aes192-ctr,aes128-ctr,arcfour256,arcfour128
MACs hmac-sha2-512,hmac-sha2-256,hmac-ripemd160,hmac-sha1

View File

@ -1,9 +0,0 @@
#!/bin/bash
SYSLOG_SERVER_IP=$(grep -oPz '(?<=\bip=)(\d+\.?){4}:\K(\d+\.?){4}' /proc/cmdline)
DEPLOYMENT_ID=$(grep -ioP '(?<=\bdeployment_id=)([0-9a-z-]+)\b' /proc/cmdline)
sed -i /etc/rsyslog.d/00-remote.conf -re "s/@SYSLOG_SERVER_IP@/$SYSLOG_SERVER_IP/"
sed -i /etc/rsyslog.d/00-remote.conf -re "s/@DEPLOYMENT_ID@/$DEPLOYMENT_ID/"
service rsyslog restart

View File

@ -1,16 +0,0 @@
[options]
broken_system_clock = true
[problems]
# Superblock last mount time is in the future (PR_0_FUTURE_SB_LAST_MOUNT).
0x000031 = {
preen_ok = true
preen_nomessage = true
}
# Superblock last write time is in the future (PR_0_FUTURE_SB_LAST_WRITE).
0x000032 = {
preen_ok = true
preen_nomessage = true
}

View File

@ -1,28 +0,0 @@
/var/log/cron
/var/log/maillog
/var/log/messages
/var/log/secure
/var/log/spooler
/var/log/mcollective.log
/var/log/nailgun-agent.log
{
# This file is used for daily log rotations, do not use size options here
sharedscripts
daily
# rotate only if 30M size or bigger
minsize 30M
maxsize 50M
# truncate file, do not delete & recreate
copytruncate
# keep logs for XXX rotations
rotate 3
# compression will be postponed to the next rotation, if uncommented
compress
# ignore missing files
missingok
# do not rotate empty files
notifempty
postrotate
/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
endscript
}

View File

@ -1,27 +0,0 @@
main_collective = mcollective
collectives = mcollective
libdir = /usr/share/mcollective/plugins
logfile = /var/log/mcollective.log
loglevel = debug
direct_addressing = 1
daemonize = 0
# Set TTL to 1.5 hours
ttl = 5400
# Plugins
securityprovider = psk
plugin.psk = unset
connector = rabbitmq
plugin.rabbitmq.vhost = mcollective
plugin.rabbitmq.pool.size = 1
plugin.rabbitmq.pool.1.host =
plugin.rabbitmq.pool.1.port = 61613
plugin.rabbitmq.pool.1.user = mcollective
plugin.rabbitmq.pool.1.password = marionette
plugin.rabbitmq.heartbeat_interval = 30
# Facts
factsource = yaml
plugin.yaml = /etc/mcollective/facts.yaml

View File

@ -1,6 +0,0 @@
#!/bin/sh -e
fix-configs-on-startup || true
flock -w 0 -o /var/lock/agent.lock -c "/opt/nailgun/bin/agent >> /var/log/nailgun-agent.log 2>&1" || true
touch /var/lock/subsys/local

View File

@ -1,6 +0,0 @@
# Log all messages with this template
$template CustomLog, "%$NOW%T%TIMESTAMP:8:$%Z %syslogseverity-text% %syslogtag% %msg%\n"
$ActionFileDefaultTemplate CustomLog
user.debug /var/log/messages

View File

@ -1,20 +0,0 @@
{
"watchlist": [
{"servers": [ {"host": "@MASTER_NODE_IP@"} ],
"watchfiles": [
{"tag": "bootstrap/dmesg", "files": ["/var/log/dmesg"]},
{"tag": "bootstrap/secure", "files": ["/var/log/secure"]},
{"tag": "bootstrap/messages", "files": ["/var/log/messages"]},
{"tag": "bootstrap/fuel-agent", "files": ["/var/log/fuel-agent.log"]},
{"tag": "bootstrap/mcollective", "log_type": "ruby",
"files": ["/var/log/mcollective.log"]},
{"tag": "bootstrap/agent", "log_type": "ruby",
"files": ["/var/log/nailgun-agent.log"]},
{"tag": "bootstrap/netprobe_sender", "log_type": "netprobe",
"files": ["/var/log/netprobe_sender.log"]},
{"tag": "bootstrap/netprobe_listener", "log_type": "netprobe",
"files": ["/var/log/netprobe_listener.log"]}
]
}
]
}

View File

@ -1,20 +0,0 @@
Protocol 2
SyslogFacility AUTHPRIV
PasswordAuthentication no
PubkeyAuthentication yes
ChallengeResponseAuthentication no
GSSAPIAuthentication no
UsePAM no
UseDNS no
# Accept locale-related environment variables
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
AcceptEnv XMODIFIERS
Subsystem sftp /usr/lib/openssh/sftp-server
# Secure Ciphers and MACs
Ciphers aes256-ctr,aes192-ctr,aes128-ctr,arcfour256,arcfour128
MACs hmac-sha2-512,hmac-sha2-256,hmac-ripemd160,hmac-sha1

View File

@ -1,30 +0,0 @@
#!/bin/sh
masternode_ip=`sed -rn 's/^.*url=http:\/\/(([0-9]{1,3}\.){3}[0-9]{1,3}).*$/\1/ p' /proc/cmdline`
mco_user=$(sed 's/\ /\n/g' /proc/cmdline | grep mco_user | awk -F\= '{print $2}')
mco_pass=$(sed 's/\ /\n/g' /proc/cmdline | grep mco_pass | awk -F\= '{print $2}')
[ -z "$mco_user" ] && mco_user="mcollective"
[ -z "$mco_pass" ] && mco_pass="marionette"
# Send logs to master node.
sed -i /etc/send2syslog.conf -re "s/@MASTER_NODE_IP@/$masternode_ip/"
/usr/bin/send2syslog.py -i < /etc/send2syslog.conf
# Set up NTP
# Disable panic about huge clock offset
sed -i '/^\s*tinker panic/ d' /etc/ntp.conf
sed -i '1 i tinker panic 0' /etc/ntp.conf
# Sync clock with master node
sed -i "/^\s*server\b/ d" /etc/ntp.conf
echo "server $masternode_ip burst iburst" >> /etc/ntp.conf
service ntp restart
# Update mcollective config
sed -i "s/^plugin.rabbitmq.pool.1.host\b.*$/plugin.rabbitmq.pool.1.host = $masternode_ip/" /etc/mcollective/server.cfg
sed -i "s/^plugin.rabbitmq.pool.1.user\b.*$/plugin.rabbitmq.pool.1.user = $mco_user/" /etc/mcollective/server.cfg
sed -i "s/^plugin.rabbitmq.pool.1.password\b.*$/plugin.rabbitmq.pool.1.password= $mco_pass/" /etc/mcollective/server.cfg
service mcollective restart

View File

@ -1,505 +0,0 @@
#!/usr/bin/env python
# Copyright 2013 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import logging
from logging.handlers import SysLogHandler
from optparse import OptionParser
import os
import re
import signal
import sys
import time
# Add syslog levels to logging module.
logging.NOTICE = 25
logging.ALERT = 60
logging.EMERG = 70
logging.addLevelName(logging.NOTICE, 'NOTICE')
logging.addLevelName(logging.ALERT, 'ALERT')
logging.addLevelName(logging.EMERG, 'EMERG')
SysLogHandler.priority_map['NOTICE'] = 'notice'
SysLogHandler.priority_map['ALERT'] = 'alert'
SysLogHandler.priority_map['EMERG'] = 'emerg'
# Define data and message format according to RFC 5424.
rfc5424_format = '{version} {timestamp} {hostname} {appname} {procid}'\
' {msgid} {structured_data} {msg}'
date_format = '%Y-%m-%dT%H:%M:%SZ'
# Define global semaphore.
sending_in_progress = 0
# Define file types.
msg_levels = {'ruby': {'regex': '(?P<level>[DIWEF]), \[[0-9-]{10}T',
'levels': {'D': logging.DEBUG,
'I': logging.INFO,
'W': logging.WARNING,
'E': logging.ERROR,
'F': logging.FATAL
}
},
'syslog': {'regex': ('[0-9-]{10}T[0-9:]{8}Z (?P<level>'
'debug|info|notice|warning|err|crit|'
'alert|emerg)'),
'levels': {'debug': logging.DEBUG,
'info': logging.INFO,
'notice': logging.NOTICE,
'warning': logging.WARNING,
'err': logging.ERROR,
'crit': logging.CRITICAL,
'alert': logging.ALERT,
'emerg': logging.EMERG
}
},
'anaconda': {'regex': ('[0-9:]{8},[0-9]+ (?P<level>'
'DEBUG|INFO|WARNING|ERROR|CRITICAL)'),
'levels': {'DEBUG': logging.DEBUG,
'INFO': logging.INFO,
'WARNING': logging.WARNING,
'ERROR': logging.ERROR,
'CRITICAL': logging.CRITICAL
}
},
'netprobe': {'regex': ('[0-9-]{10} [0-9:]{8},[0-9]+ (?P<level>'
'DEBUG|INFO|WARNING|ERROR|CRITICAL)'),
'levels': {'DEBUG': logging.DEBUG,
'INFO': logging.INFO,
'WARNING': logging.WARNING,
'ERROR': logging.ERROR,
'CRITICAL': logging.CRITICAL
}
}
}
relevel_errors = {
'anaconda': [
{
'regex': 'Error downloading \
http://.*/images/(product|updates).img: HTTP response code said error',
'levelfrom': logging.ERROR,
'levelto': logging.WARNING
},
{
'regex': 'got to setupCdrom without a CD device',
'levelfrom': logging.ERROR,
'levelto': logging.WARNING
}
]
}
# Create a main logger.
logging.basicConfig(format='%(levelname)s: %(message)s')
main_logger = logging.getLogger()
main_logger.setLevel(logging.NOTSET)
class WatchedFile:
"""WatchedFile(filename) => Object that read lines from file if exist."""
def __init__(self, name):
self.name = name
self.fo = None
self.where = 0
def reset(self):
if self.fo:
self.fo.close()
self.fo = None
self.where = 0
def _checkRewrite(self):
try:
if os.stat(self.name)[6] < self.where:
self.reset()
except OSError:
self.close()
def readLines(self):
"""Return list of last append lines from file if exist."""
self._checkRewrite()
if not self.fo:
try:
self.fo = open(self.name, 'r')
except IOError:
return ()
lines = self.fo.readlines()
self.where = self.fo.tell()
return lines
def close(self):
self.reset()
class WatchedGroup:
"""Can send data from group of specified files to specified servers."""
def __init__(self, servers, files, name):
self.servers = servers
self.files = files
self.log_type = files.get('log_type', 'syslog')
self.name = name
self._createLogger()
def _createLogger(self):
self.watchedfiles = []
logger = logging.getLogger(self.name)
logger.setLevel(logging.NOTSET)
logger.propagate = False
# Create log formatter.
format_dict = {'version': '1',
'timestamp': '%(asctime)s',
'hostname': config['hostname'],
'appname': self.files['tag'],
'procid': '-',
'msgid': '-',
'structured_data': '-',
'msg': '%(message)s'
}
log_format = rfc5424_format.format(**format_dict)
formatter = logging.Formatter(log_format, date_format)
# Add log handler for each server.
for server in self.servers:
port = 'port' in server and server['port'] or 514
syslog = SysLogHandler((server["host"], port))
syslog.setFormatter(formatter)
logger.addHandler(syslog)
self.logger = logger
# Create WatchedFile objects from list of files.
for name in self.files['files']:
self.watchedfiles.append(WatchedFile(name))
def send(self):
"""Send append data from files to servers."""
for watchedfile in self.watchedfiles:
for line in watchedfile.readLines():
line = line.strip()
level = self._get_msg_level(line, self.log_type)
# Get rid of duplicated information in anaconda logs
line = re.sub(
msg_levels[self.log_type]['regex'] + "\s*:?\s?",
"",
line
)
# Ignore meaningless errors
try:
for r in relevel_errors[self.log_type]:
if level == r['levelfrom'] and \
re.match(r['regex'], line):
level = r['levelto']
except KeyError:
pass
self.logger.log(level, line)
main_logger and main_logger.log(
level,
'From file "%s" send: %s' % (watchedfile.name, line)
)
@staticmethod
def _get_msg_level(line, log_type):
if log_type in msg_levels:
msg_type = msg_levels[log_type]
regex = re.match(msg_type['regex'], line)
if regex:
return msg_type['levels'][regex.group('level')]
return logging.INFO
def sig_handler(signum, frame):
"""Send all new data when signal arrived."""
if not sending_in_progress:
send_all()
exit(signum)
else:
config['run_once'] = True
def send_all():
"""Send any updates."""
for group in watchlist:
group.send()
def main_loop():
"""Periodicaly call sendlogs() for each group in watchlist."""
signal.signal(signal.SIGINT, sig_handler)
signal.signal(signal.SIGTERM, sig_handler)
while watchlist:
time.sleep(0.5)
send_all()
# If asked to run_once, exit now
if config['run_once']:
break
class Config:
"""Collection of config generation methods.
Usage: config = Config.getConfig()
"""
@classmethod
def getConfig(cls):
"""Generate config from command line arguments and config file."""
# example_config = {
# "daemon": True,
# "run_once": False,
# "debug": False,
# "watchlist": [
# {"servers": [ {"host": "localhost", "port": 514} ],
# "watchfiles": [
# {"tag": "anaconda",
# "log_type": "anaconda",
# "files": ["/tmp/anaconda.log",
# "/mnt/sysimage/root/install.log"]
# }
# ]
# }
# ]
# }
default_config = {"daemon": True,
"run_once": False,
"debug": False,
"hostname": cls._getHostname(),
"watchlist": []
}
# First use default config as running config.
config = dict(default_config)
# Get command line options and validate it.
cmdline = cls.cmdlineParse()[0]
# Check config file source and read it.
if cmdline.config_file or cmdline.stdin_config:
try:
if cmdline.stdin_config is True:
fo = sys.stdin
else:
fo = open(cmdline.config_file, 'r')
parsed_config = json.load(fo)
if cmdline.debug:
print(parsed_config)
except IOError: # Raised if IO operations failed.
main_logger.error("Can not read config file %s\n" %
cmdline.config_file)
exit(1)
except ValueError as e: # Raised if json parsing failed.
main_logger.error("Can not parse config file. %s\n" %
e.message)
exit(1)
# Validate config from config file.
cls.configValidate(parsed_config)
# Copy gathered config from config file to running config
# structure.
for key, value in parsed_config.items():
config[key] = value
else:
# If no config file specified use watchlist setting from
# command line.
watchlist = {"servers": [{"host": cmdline.host,
"port": cmdline.port}],
"watchfiles": [{"tag": cmdline.tag,
"log_type": cmdline.log_type,
"files": cmdline.watchfiles}]}
config['watchlist'].append(watchlist)
# Apply behavioural command line options to running config.
if cmdline.no_daemon:
config["daemon"] = False
if cmdline.run_once:
config["run_once"] = True
if cmdline.debug:
config["debug"] = True
return config
@staticmethod
def _getHostname():
"""Generate hostname by BOOTIF kernel option or use os.uname()."""
with open('/proc/cmdline') as fo:
cpu_cmdline = fo.readline().strip()
regex = re.search('(?<=BOOTIF=)([0-9a-fA-F-]*)', cpu_cmdline)
if regex:
mac = regex.group(0).upper()
return ''.join(mac.split('-'))
return os.uname()[1]
@staticmethod
def cmdlineParse():
"""Parse command line config options."""
parser = OptionParser()
parser.add_option("-c", "--config", dest="config_file", metavar="FILE",
help="Read config from FILE.")
parser.add_option("-i", "--stdin", dest="stdin_config", default=False,
action="store_true", help="Read config from Stdin.")
# FIXIT Add optionGroups.
parser.add_option("-r", "--run-once", dest="run_once",
action="store_true", help="Send all data and exit.")
parser.add_option("-n", "--no-daemon", dest="no_daemon",
action="store_true", help="Do not daemonize.")
parser.add_option("-d", "--debug", dest="debug",
action="store_true", help="Print debug messages.")
parser.add_option("-t", "--tag", dest="tag", metavar="TAG",
help="Set tag of sending messages as TAG.")
parser.add_option("-T", "--type", dest="log_type", metavar="TYPE",
default='syslog',
help="Set type of files as TYPE"
"(default: %default).")
parser.add_option("-f", "--watchfile", dest="watchfiles",
action="append",
metavar="FILE", help="Add FILE to watchlist.")
parser.add_option("-s", "--host", dest="host", metavar="HOSTNAME",
help="Set destination as HOSTNAME.")
parser.add_option("-p", "--port", dest="port", type="int", default=514,
metavar="PORT",
help="Set remote port as PORT (default: %default).")
options, args = parser.parse_args()
# Validate gathered options.
if options.config_file and options.stdin_config:
parser.error("You must not set both options --config"
" and --stdin at the same time.")
exit(1)
if ((options.config_file or options.stdin_config) and
(options.tag or options.watchfiles or options.host)):
main_logger.warning("If --config or --stdin is set up options"
" --tag, --watchfile, --type,"
" --host and --port will be ignored.")
if (not (options.config_file or options.stdin_config) and
not (options.tag and options.watchfiles and options.host)):
parser.error("Options --tag, --watchfile and --host"
" must be set up at the same time.")
exit(1)
return options, args
@staticmethod
def _checkType(value, value_type, value_name='', msg=None):
"""Check correctness of type of value and exit if not."""
if not isinstance(value, value_type):
message = msg or "Value %r in config have type %r but"\
" %r is expected." %\
(value_name, type(value).__name__, value_type.__name__)
main_logger.error(message)
exit(1)
@classmethod
def configValidate(cls, config):
"""Validate types and names of data items in config."""
cls._checkType(config, dict, msg='Config must be a dict.')
for key in ("daemon", "run_once", "debug"):
if key in config:
cls._checkType(config[key], bool, key)
key = "hostname"
if key in config:
cls._checkType(config[key], basestring, key)
key = "watchlist"
if key in config:
cls._checkType(config[key], list, key)
else:
main_logger.error("There must be key %r in config." % key)
exit(1)
for item in config["watchlist"]:
cls._checkType(item, dict, "watchlist[n]")
key, name = "servers", "watchlist[n] => servers"
if key in item:
cls._checkType(item[key], list, name)
else:
main_logger.error("There must be key %r in %s in config." %
(key, '"watchlist[n]" item'))
exit(1)
key, name = "watchfiles", "watchlist[n] => watchfiles"
if key in item:
cls._checkType(item[key], list, name)
else:
main_logger.error("There must be key %r in %s in config." %
(key, '"watchlist[n]" item'))
exit(1)
for item2 in item["servers"]:
cls._checkType(item2, dict, "watchlist[n] => servers[n]")
key, name = "host", "watchlist[n] => servers[n] => host"
if key in item2:
cls._checkType(item2[key], basestring, name)
else:
main_logger.error("There must be key %r in %s in config." %
(key,
'"watchlist[n] => servers[n]" item'))
exit(1)
key, name = "port", "watchlist[n] => servers[n] => port"
if key in item2:
cls._checkType(item2[key], int, name)
for item2 in item["watchfiles"]:
cls._checkType(item2, dict, "watchlist[n] => watchfiles[n]")
key, name = "tag", "watchlist[n] => watchfiles[n] => tag"
if key in item2:
cls._checkType(item2[key], basestring, name)
else:
main_logger.error("There must be key %r in %s in config." %
(key,
'"watchlist[n] => watchfiles[n]" item'))
exit(1)
key = "log_type"
name = "watchlist[n] => watchfiles[n] => log_type"
if key in item2:
cls._checkType(item2[key], basestring, name)
key, name = "files", "watchlist[n] => watchfiles[n] => files"
if key in item2:
cls._checkType(item2[key], list, name)
else:
main_logger.error("There must be key %r in %s in config." %
(key,
'"watchlist[n] => watchfiles[n]" item'))
exit(1)
for item3 in item2["files"]:
name = "watchlist[n] => watchfiles[n] => files[n]"
cls._checkType(item3, basestring, name)
# Create global config.
config = Config.getConfig()
# Create list of WatchedGroup objects with different log names.
watchlist = []
i = 0
for item in config["watchlist"]:
for files in item['watchfiles']:
watchlist.append(WatchedGroup(item['servers'], files, str(i)))
i = i + 1
# Fork and loop
if config["daemon"]:
if not os.fork():
# Redirect the standard I/O file descriptors to the specified file.
main_logger = None
DEVNULL = getattr(os, "devnull", "/dev/null")
os.open(DEVNULL, os.O_RDWR) # standard input (0)
os.dup2(0, 1) # Duplicate standard input to standard output (1)
os.dup2(0, 2) # Duplicate standard input to standard error (2)
main_loop()
sys.exit(1)
sys.exit(0)
else:
if not config['debug']:
main_logger = None
main_loop()

View File

@ -1,38 +0,0 @@
#!/usr/bin/env ruby
require 'hiera'
ENV['LANG'] = 'C'
hiera = Hiera.new(:config => '/etc/hiera.yaml')
glanced = hiera.lookup 'glance', {} , {}
management_vip = hiera.lookup 'management_vip', nil, {}
auth_addr = hiera.lookup 'service_endpoint', "#{management_vip}", {}
tenant_name = glanced['tenant'].nil? ? "services" : glanced['tenant']
user_name = glanced['user'].nil? ? "glance" : glanced['user']
endpoint_type = glanced['endpoint_type'].nil? ? "internalURL" : glanced['endpoint_type']
region_name = hiera.lookup 'region', 'RegionOne', {}
ironic_hash = hiera.lookup 'fuel-plugin-ironic', {}, {}
ironic_swift_tempurl_key = ironic_hash['password'].nil? ? "ironic" : ironic_hash['password']
ENV['OS_TENANT_NAME']="#{tenant_name}"
ENV['OS_USERNAME']="#{user_name}"
ENV['OS_PASSWORD']="#{glanced['user_password']}"
ENV['OS_AUTH_URL']="http://#{auth_addr}:5000/v2.0"
ENV['OS_ENDPOINT_TYPE'] = "#{endpoint_type}"
ENV['OS_REGION_NAME']="#{region_name}"
command = <<-EOF
/usr/bin/swift post -m 'Temp-URL-Key:#{ironic_swift_tempurl_key}'
EOF
puts command
5.times.each do |retries|
sleep 10 if retries > 0
stdout = `#{command}`
return_code = $?.exitstatus
puts stdout
exit 0 if return_code == 0
end
puts "Secret key registration have FAILED!"
exit 1

View File

@ -1,25 +0,0 @@
notice('MODULAR: ironic/baremetal-firewall.pp')
$network_scheme = hiera('network_scheme', {})
prepare_network_config($network_scheme)
$baremetal_int = get_network_role_property('ironic/baremetal', 'interface')
$nodes_hash = hiera('nodes', {})
$roles = node_roles($nodes_hash, hiera('uid'))
if ! member($roles, 'controller') or ! member($roles, 'primary-controller') or ! member($roles, 'ironic') {
firewallchain { 'baremetal:filter:IPv4':
ensure => present,
} ->
firewall { '999 drop all':
chain => 'baremetal',
action => 'drop',
proto => 'all',
} ->
firewall {'00 baremetal-filter ':
proto => 'all',
iniface => $baremetal_int,
jump => 'baremetal',
require => Class['openstack::firewall'],
}
class { 'openstack::firewall':}
}

View File

@ -1,51 +0,0 @@
notice('MODULAR: ironic/db.pp')
$node_name = hiera('node_name')
$ironic_hash = hiera_hash('fuel-plugin-ironic', {})
$mysql_hash = hiera_hash('mysql', {})
$mysql_root_user = pick($mysql_hash['root_user'], 'root')
$mysql_db_create = pick($mysql_hash['db_create'], true)
$mysql_root_password = $mysql_hash['root_password']
$db_user = pick($ironic_hash['db_user'], 'ironic')
$db_name = pick($ironic_hash['db_name'], 'ironic')
$db_password = pick($ironic_hash['password'], 'ironic')
$db_host = pick($ironic_hash['db_host'], $database_vip, 'localhost')
$db_create = pick($ironic_hash['db_create'], $mysql_db_create)
$db_root_user = pick($ironic_hash['root_user'], $mysql_root_user)
$db_root_password = pick($ironic_hash['root_password'], $mysql_root_password)
$allowed_hosts = [ $node_name, 'localhost', '127.0.0.1', '%' ]
if $ironic_hash['metadata']['enabled'] and $db_create {
class { 'galera::client':
custom_setup_class => hiera('mysql_custom_setup_class', 'galera'),
}
class { 'ironic::db::mysql':
user => $db_user,
password => $db_password,
dbname => $db_name,
allowed_hosts => $allowed_hosts,
}
class { 'osnailyfacter::mysql_access':
db_host => $db_host,
db_user => $db_root_user,
db_password => $db_root_password,
}
Class['galera::client'] ->
Class['osnailyfacter::mysql_access'] ->
Class['ironic::db::mysql']
}
class mysql::config {}
include mysql::config
class mysql::server {}
include mysql::server

View File

@ -1,93 +0,0 @@
notice('MODULAR: ironic/haproxy.pp')
$network_metadata = hiera_hash('network_metadata')
$storage_hash = hiera_hash('storage', {})
$public_ssl_hash = hiera('public_ssl')
$ironic_api_nodes = get_nodes_hash_by_roles($network_metadata, ['primary-controller', 'controller'])
$ironic_address_map = get_node_to_ipaddr_map_by_network_role($ironic_api_nodes, 'ironic/api')
$ironic_server_names = hiera_array('ironic_names', keys($ironic_address_map))
$ironic_ipaddresses = hiera_array('ironic_ipaddresses', values($ironic_address_map))
$public_virtual_ip = hiera('public_vip')
$internal_virtual_ip = hiera('management_vip')
$baremetal_virtual_ip = $network_metadata['vips']['baremetal']['ipaddr']
if !($storage_hash['images_ceph'] and $storage_hash['objects_ceph']) and !$storage_hash['images_vcenter'] {
$use_swift = true
} else {
$use_swift = false
}
if !($use_swift) and ($storage_hash['objects_ceph']) {
$use_radosgw = true
} else {
$use_radosgw = false
}
Openstack::Ha::Haproxy_service {
ipaddresses => $ironic_ipaddresses,
public_virtual_ip => $public_virtual_ip,
server_names => $ironic_server_names,
public => true,
public_ssl => $public_ssl_hash['services'],
haproxy_config_options => {
option => ['httpchk GET /', 'httplog','httpclose'],
},
}
openstack::ha::haproxy_service { 'ironic-api':
order => '180',
listen_port => 6385,
internal_virtual_ip => $internal_virtual_ip,
}
openstack::ha::haproxy_service { 'ironic-baremetal':
order => '185',
listen_port => 6385,
public => false,
public_ssl => false,
public_virtual_ip => false,
internal_virtual_ip => $baremetal_virtual_ip,
}
if $use_swift {
$swift_proxies_address_map = get_node_to_ipaddr_map_by_network_role(hiera_hash('swift_proxies', undef), 'swift/api')
$swift_server_names = hiera_array('swift_server_names', keys($swift_proxies_address_map))
$swift_ipaddresses = hiera_array('swift_ipaddresses', values($swift_proxies_address_map))
openstack::ha::haproxy_service { 'swift-baremetal':
order => '125',
listen_port => 8080,
ipaddresses => $swift_ipaddresses,
server_names => $swift_server_names,
public => false,
public_ssl => false,
public_virtual_ip => false,
internal_virtual_ip => $baremetal_virtual_ip,
haproxy_config_options => {
'option' => ['httpchk', 'httplog', 'httpclose'],
},
balancermember_options => 'check port 49001 inter 15s fastinter 2s downinter 8s rise 3 fall 3',
}
}
if $use_radosgw {
$rgw_address_map = get_node_to_ipaddr_map_by_network_role(hiera_hash('ceph_rgw_nodes'), 'ceph/radosgw')
$rgw_server_names = hiera_array('radosgw_server_names', keys($rgw_address_map))
$rgw_ipaddresses = hiera_array('radosgw_ipaddresses', values($rgw_address_map))
openstack::ha::haproxy_service { 'radosgw-baremetal':
order => '135',
listen_port => 8080,
balancermember_port => 6780,
ipaddresses => $rgw_ipaddresses,
server_names => $rgw_server_names,
public => false,
public_ssl => false,
public_virtual_ip => false,
internal_virtual_ip => $baremetal_virtual_ip,
haproxy_config_options => {
'option' => ['httplog', 'httpchk GET /'],
},
}
}

View File

@ -1,91 +0,0 @@
notice('MODULAR: ironic/ironic-compute.pp')
$ironic_hash = hiera_hash('fuel-plugin-ironic', {})
$nova_hash = hiera_hash('nova', {})
$management_vip = hiera('management_vip')
$database_vip = hiera('database_vip', $management_vip)
$keystone_endpoint = hiera('keystone_endpoint', $management_vip)
$neutron_endpoint = hiera('neutron_endpoint', $management_vip)
$ironic_endpoint = hiera('ironic_endpoint', $management_vip)
$glance_api_servers = hiera('glance_api_servers', "${management_vip}:9292")
$debug = hiera('debug', false)
$verbose = hiera('verbose', true)
$use_syslog = hiera('use_syslog', true)
$syslog_log_facility_ironic = hiera('syslog_log_facility_ironic', 'LOG_LOCAL0')
$syslog_log_facility_nova = hiera('syslog_log_facility_nova', 'LOG_LOCAL6')
$amqp_hosts = hiera('amqp_hosts')
$rabbit_hash = hiera('rabbit_hash')
$nova_report_interval = hiera('nova_report_interval')
$nova_service_down_time = hiera('nova_service_down_time')
$neutron_config = hiera_hash('quantum_settings')
$ironic_tenant = pick($ironic_hash['tenant'],'services')
$ironic_user = pick($ironic_hash['user'],'ironic')
$ironic_user_password = pick($ironic_hash['password'],'ironic')
$db_host = pick($nova_hash['db_host'], $database_vip)
$db_user = pick($nova_hash['db_user'], 'nova')
$db_name = pick($nova_hash['db_name'], 'nova')
$db_password = pick($nova_hash['db_password'], 'nova')
$database_connection = "mysql://${db_name}:${db_password}@${db_host}/${db_name}?read_timeout=60"
$memcache_nodes = get_nodes_hash_by_roles(hiera('network_metadata'), hiera('memcache_roles'))
$cache_server_ip = ipsort(values(get_node_to_ipaddr_map_by_network_role($memcache_nodes,'mgmt/memcache')))
$memcached_addresses = suffix($cache_server_ip, inline_template(":<%= @cache_server_port %>"))
$notify_on_state_change = 'vm_and_task_state'
class { '::nova':
install_utilities => false,
ensure_package => installed,
database_connection => $database_connection,
rpc_backend => 'nova.openstack.common.rpc.impl_kombu',
#FIXME(bogdando) we have to split amqp_hosts until all modules synced
rabbit_hosts => split($amqp_hosts, ','),
rabbit_userid => $rabbit_hash['user'],
rabbit_password => $rabbit_hash['password'],
image_service => 'nova.image.glance.GlanceImageService',
glance_api_servers => $glance_api_servers,
verbose => $verbose,
debug => $debug,
use_syslog => $use_syslog,
log_facility => $syslog_log_facility_nova,
state_path => $nova_hash['state_path'],
report_interval => $nova_report_interval,
service_down_time => $nova_service_down_time,
notify_on_state_change => $notify_on_state_change,
memcached_servers => $memcached_addresses,
}
class { '::nova::compute':
ensure_package => installed,
enabled => true,
vnc_enabled => false,
force_config_drive => $nova_hash['force_config_drive'],
#NOTE(bogdando) default became true in 4.0.0 puppet-nova (was false)
neutron_enabled => true,
default_availability_zone => $nova_hash['default_availability_zone'],
default_schedule_zone => $nova_hash['default_schedule_zone'],
reserved_host_memory => '0',
}
class { 'nova::compute::ironic':
admin_url => "http://${keystone_endpoint}:35357/v2.0",
admin_user => $ironic_user,
admin_tenant_name => $ironic_tenant,
admin_passwd => $ironic_user_password,
api_endpoint => "http://${ironic_endpoint}:6385/v1",
}
class { 'nova::network::neutron':
neutron_admin_password => $neutron_config['keystone']['admin_password'],
neutron_url => "http://${neutron_endpoint}:9696",
neutron_admin_auth_url => "http://${keystone_endpoint}:35357/v2.0",
}
file { '/etc/nova/nova-compute.conf':
ensure => absent,
require => Package['nova-compute'],
} ~> Service['nova-compute']

View File

@ -1,30 +0,0 @@
notice('MODULAR: ironic/ironic-conductor-config.pp')
$ironic_hash = hiera_hash('fuel-plugin-ironic', {})
$management_vip = hiera('management_vip')
$keystone_endpoint = hiera('keystone_endpoint', $management_vip)
$ironic_tenant = pick($ironic_hash['tenant'],'services')
$ironic_user = pick($ironic_hash['user'],'ironic')
$ironic_user_password = pick($ironic_hash['password'],'ironic')
include ::ironic::params
ironic_images_setter {'ironic_images':
ensure => present,
auth_url => "http://${keystone_endpoint}:5000/v2.0/",
auth_username => $ironic_user,
auth_password => $ironic_user_password,
auth_tenant_name => $ironic_tenant,
glance_url => "http://${management_vip}:9292/v2.0/",
}
service { 'ironic-conductor':
ensure => 'running',
name => $::ironic::params::conductor_service,
enable => true,
hasstatus => true,
tag => 'ironic-service',
}
Ironic_images_setter<||> ~> Service['ironic-conductor']

View File

@ -1,128 +0,0 @@
notice('MODULAR: ironic/ironic-conductor.pp')
$network_scheme = hiera('network_scheme', {})
prepare_network_config($network_scheme)
$baremetal_address = get_network_role_property('ironic/baremetal', 'ipaddr')
$ironic_hash = hiera_hash('fuel-plugin-ironic', {})
$management_vip = hiera('management_vip')
$network_metadata = hiera_hash('network_metadata', {})
$baremetal_vip = $network_metadata['vips']['baremetal']['ipaddr']
$database_vip = hiera('database_vip', $management_vip)
$keystone_endpoint = hiera('keystone_endpoint', $management_vip)
$neutron_endpoint = hiera('neutron_endpoint', $management_vip)
$glance_api_servers = hiera('glance_api_servers', "${management_vip}:9292")
$amqp_hosts = hiera('amqp_hosts')
$rabbit_hosts = split($amqp_hosts, ',')
$debug = hiera('debug', false)
$verbose = hiera('verbose', true)
$use_syslog = hiera('use_syslog', true)
$syslog_log_facility_ironic = hiera('syslog_log_facility_ironic', 'LOG_USER')
$rabbit_hash = hiera('rabbit_hash')
$rabbit_ha_queues = hiera('rabbit_ha_queues')
$ironic_tenant = pick($ironic_hash['tenant'],'services')
$ironic_user = pick($ironic_hash['user'],'ironic')
$ironic_user_password = pick($ironic_hash['password'],'ironic')
$ironic_swift_tempurl_key = pick($ironic_hash['password'],'ironic')
$db_host = pick($ironic_hash['db_host'], $database_vip)
$db_user = pick($ironic_hash['db_user'], 'ironic')
$db_name = pick($ironic_hash['db_name'], 'ironic')
$db_password = pick($ironic_hash['password'], 'ironic')
$database_connection = "mysql://${db_name}:${db_password}@${db_host}/${db_name}?charset=utf8&read_timeout=60"
include ::rsyslog::params
$tftp_root = "/var/lib/ironic/tftpboot"
class { '::ironic':
verbose => $verbose,
debug => $debug,
enabled_drivers => ['fuel_ssh', 'fuel_ipmitool', 'fake'],
rabbit_hosts => $rabbit_hosts,
rabbit_port => 5673,
rabbit_userid => $rabbit_hash['user'],
rabbit_password => $rabbit_hash['password'],
amqp_durable_queues => $rabbit_ha_queues,
use_syslog => $use_syslog,
log_facility => $syslog_log_facility_ironic,
database_connection => $database_connection,
glance_api_servers => $glance_api_servers,
}
class { '::ironic::client': }
class { '::ironic::conductor': }
class { '::ironic::drivers::pxe':
tftp_server => $baremetal_address,
tftp_root => $tftp_root,
tftp_master_path => "${tftp_root}/master_images",
}
ironic_config {
'neutron/url': value => "http://${neutron_endpoint}:9696";
'keystone_authtoken/auth_uri': value => "http://${keystone_endpoint}:5000/";
'keystone_authtoken/auth_host': value => $keystone_endpoint;
'keystone_authtoken/admin_tenant_name': value => $ironic_tenant;
'keystone_authtoken/admin_user': value => $ironic_user;
'keystone_authtoken/admin_password': value => $ironic_user_password, secret => true;
'glance/swift_temp_url_key': value => $ironic_swift_tempurl_key;
'glance/swift_endpoint_url': value => "http://${baremetal_vip}:8080";
#'glance/swift_account': value => "AUTH_${services_tenant_id}";
'conductor/api_url': value => "http://${baremetal_vip}:6385";
}
file { $tftp_root:
ensure => directory,
owner => 'ironic',
group => 'ironic',
mode => 755,
require => Class['ironic'],
}
file { "$tftp_root/pxelinux.0":
ensure => present,
source => '/usr/lib/syslinux/pxelinux.0',
require => Package['syslinux'],
}
file { "${tftp_root}/map-file":
content => "r ^([^/]) ${tftp_root}/\\1",
}
class { '::tftp':
directory => $tftp_root,
options => "--map-file ${tftp_root}/map-file",
inetd => false,
require => File["${tftp_root}/map-file"],
}
package { 'syslinux':
ensure => 'present',
}
package { 'ipmitool':
ensure => 'present',
before => Class['::ironic::conductor'],
}
file { "/etc/ironic/fuel_key":
ensure => present,
source => '/var/lib/astute/ironic/bootstrap.rsa',
owner => 'ironic',
group => 'ironic',
mode => 600,
require => Class['ironic'],
}
file { "${rsyslog::params::rsyslog_d}55-server-ironic.conf":
content => template("ironic/55-server-ironic.conf.erb"),
} ~>
service { $rsyslog::params::service_name:
ensure => running,
enable => true,
}

View File

@ -1,105 +0,0 @@
notice('MODULAR: ironic/ironic.pp')
$ironic_hash = hiera_hash('fuel-plugin-ironic', {})
$nova_hash = hiera_hash('nova_hash', {})
$access_hash = hiera_hash('access',{})
$public_vip = hiera('public_vip')
$management_vip = hiera('management_vip')
$public_ssl_hash = hiera('public_ssl')
$network_metadata = hiera_hash('network_metadata', {})
$baremetal_vip = $network_metadata['vips']['baremetal']['ipaddr']
$database_vip = hiera('database_vip', $management_vip)
$keystone_endpoint = hiera('keystone_endpoint', $management_vip)
$neutron_endpoint = hiera('neutron_endpoint', $management_vip)
$glance_api_servers = hiera('glance_api_servers', "${management_vip}:9292")
$debug = hiera('debug', false)
$verbose = hiera('verbose', true)
$use_syslog = hiera('use_syslog', true)
$syslog_log_facility_ironic = hiera('syslog_log_facility_ironic', 'LOG_USER')
$rabbit_hash = hiera_hash('rabbit_hash', {})
$rabbit_ha_queues = hiera('rabbit_ha_queues')
$amqp_hosts = hiera('amqp_hosts')
$rabbit_hosts = split($amqp_hosts, ',')
$neutron_config = hiera_hash('quantum_settings')
$db_host = pick($ironic_hash['db_host'], $database_vip)
$db_user = pick($ironic_hash['db_user'], 'ironic')
$db_name = pick($ironic_hash['db_name'], 'ironic')
$db_password = pick($ironic_hash['password'], 'ironic')
$database_connection = "mysql://${db_name}:${db_password}@${db_host}/${db_name}?charset=utf8&read_timeout=60"
$public_address = $public_ssl_hash['services'] ? {
true => $public_ssl_hash['hostname'],
default => $public_vip,
}
$public_protocol = $public_ssl_hash['services'] ? {
true => 'https',
default => 'http',
}
$region = hiera('region', 'RegionOne')
$public_url = "${public_protocol}://${public_address}:6385"
$admin_url = "http://${management_vip}:6385"
$internal_url = "http://${management_vip}:6385"
$ironic_tenant = pick($ironic_hash['tenant'],'services')
$ironic_user = pick($ironic_hash['user'],'ironic')
$ironic_user_password = pick($ironic_hash['password'],'ironic')
prepare_network_config(hiera('network_scheme', {}))
if $ironic_hash['metadata']['enabled'] {
class { 'ironic':
verbose => $verbose,
debug => $debug,
enabled_drivers => ['fuel_ssh', 'fuel_ipmitool', 'fake'],
rabbit_hosts => $rabbit_hosts,
rabbit_port => 5673,
rabbit_userid => $rabbit_hash['user'],
rabbit_password => $rabbit_hash['password'],
amqp_durable_queues => $rabbit_ha_queues,
use_syslog => $use_syslog,
log_facility => $syslog_log_facility_ironic,
database_connection => $database_connection,
glance_api_servers => $glance_api_servers,
}
class { 'ironic::client': }
class { 'ironic::api':
host_ip => get_network_role_property('ironic/api', 'ipaddr'),
auth_host => $keystone_endpoint,
admin_tenant_name => $ironic_tenant,
admin_user => $ironic_user,
admin_password => $ironic_user_password,
neutron_url => "http://${neutron_endpoint}:9696",
}
class { 'ironic::keystone::auth':
password => $ironic_user_password,
region => $region,
public_url => $public_url,
internal_url => $internal_url,
admin_url => $admin_url,
}
firewall { '207 ironic-api' :
dport => '6385',
proto => 'tcp',
action => 'accept',
}
nova_config {
'DEFAULT/scheduler_host_manager': value => 'nova.scheduler.ironic_host_manager.IronicHostManager';
}
include ::nova::params
service { 'nova-scheduler':
ensure => 'running',
name => $::nova::params::scheduler_service_name,
}
Nova_config<| |> ~> Service['nova-scheduler']
}

View File

@ -1,62 +0,0 @@
notice('MODULAR: ironic/network-conductor.pp')
$network_scheme = hiera('network_scheme', {})
prepare_network_config($network_scheme)
$baremetal_int = get_network_role_property('ironic/baremetal', 'interface')
$baremetal_ipaddr = get_network_role_property('ironic/baremetal', 'ipaddr')
$baremetal_network = get_network_role_property('ironic/baremetal', 'network')
# Firewall
###############################
firewallchain { 'baremetal:filter:IPv4':
ensure => present,
} ->
firewall { '100 allow rsyslog':
chain => 'baremetal',
source => $baremetal_network,
destination => $baremetal_ipaddr,
proto => 'udp',
dport => '514',
action => 'accept',
} ->
firewall { '101 allow TFTP':
chain => 'baremetal',
source => $baremetal_network,
destination => $baremetal_ipaddr,
proto => 'udp',
dport => '69',
action => 'accept',
} ->
firewall { '900 allow related':
chain => 'baremetal',
source => $baremetal_network,
destination => $baremetal_ipaddr,
proto => 'all',
state => ['RELATED', 'ESTABLISHED'],
action => 'accept',
} ->
firewall { '999 drop all':
chain => 'baremetal',
action => 'drop',
proto => 'all',
} ->
firewall {'00 baremetal-filter ':
proto => 'all',
iniface => $baremetal_int,
jump => 'baremetal',
require => Class['openstack::firewall'],
}
exec { 'fix_ipt_modules':
command => '/bin/sed -i "s/^IPT_MODULES=.*/IPT_MODULES=\"nf_conntrack_ftp nf_nat_ftp nf_conntrack_netbios_ns nf_conntrack_tftp\"/g" /etc/default/ufw',
unless => '/bin/grep "^IPT_MODULES=.*nf_conntrack_tftp" /etc/default/ufw > /dev/null',
notify => Exec['load_tftp_mod']
}
exec { 'load_tftp_mod':
command => '/sbin/modprobe nf_conntrack_tftp',
refreshonly => true,
}
class { 'openstack::firewall':}

View File

@ -1,42 +0,0 @@
notice('MODULAR: ironic/network-openstack.pp')
$network_scheme = hiera('network_scheme', {})
prepare_network_config($network_scheme)
$neutron_config = hiera_hash('quantum_settings')
$pnets = $neutron_config['L2']['phys_nets']
$baremetal_network = get_network_role_property('ironic/baremetal', 'network')
$nameservers = $neutron_config['predefined_networks']['net04']['L3']['nameservers']
$ironic_hash = hiera_hash('fuel-plugin-ironic', {})
$baremetal_L3_allocation_pool = $ironic_hash['l3_allocation_pool']
$baremetal_L3_gateway = $ironic_hash['l3_gateway']
# Predefined network
###############################
$netdata = {
'L2' => {
network_type => 'flat',
physnet => 'physnet-ironic',
router_ext => 'false',
segment_id => 'null'
},
'L3' => {
enable_dhcp => true,
floating => $baremetal_L3_allocation_pool,
gateway => $baremetal_L3_gateway,
nameservers => $nameservers,
subnet => $baremetal_network
},
'shared' => 'true',
'tenant' => 'admin',
}
openstack::network::create_network{'baremetal':
netdata => $netdata,
segmentation_type => 'flat',
} ->
neutron_router_interface { "router04:baremetal__subnet":
ensure => present,
}

View File

@ -1,21 +0,0 @@
notice('MODULAR: ironic/network-ovs.pp')
$network_scheme = hiera('network_scheme', {})
prepare_network_config($network_scheme)
$baremetal_int = get_network_role_property('ironic/baremetal', 'interface')
$sdn = generate_network_config()
# OVS patch
###############################
class { 'l23network':
use_ovs => true,
} ->
l23network::l2::bridge { 'br-ironic':
provider => 'ovs'
} ->
l23network::l2::patch { "patch__${baremetal_int}--br-ironic":
bridges => ['br-ironic', $baremetal_int],
provider => 'ovs',
mtu => 65000,
}

View File

@ -1,43 +0,0 @@
notice('MODULAR: ironic/network-physnets-conductor.pp')
$network_scheme = hiera('network_scheme', {})
prepare_network_config($network_scheme)
$neutron_config = hiera_hash('quantum_settings')
$pnets = $neutron_config['L2']['phys_nets']
$baremetal_network = get_network_role_property('ironic/baremetal', 'network')
$nameservers = $neutron_config['predefined_networks']['net04']['L3']['nameservers']
$ironic_hash = hiera_hash('fuel-plugin-ironic', {})
$baremetal_L3_allocation_pool = $ironic_hash['l3_allocation_pool']
$baremetal_L3_gateway = $ironic_hash['l3_gateway']
# Physnets
###############################
if $pnets['physnet1'] {
$physnet1 = "physnet1:${pnets['physnet1']['bridge']}"
}
if $pnets['physnet2'] {
$physnet2 = "physnet2:${pnets['physnet2']['bridge']}"
}
$physnet_ironic = "physnet-ironic:br-ironic"
$physnets_array = [$physnet1, $physnet2, $physnet_ironic]
$bridge_mappings = delete_undef_values($physnets_array)
$br_map_str = join($bridge_mappings, ',')
neutron_agent_ovs {
'ovs/bridge_mappings': value => $br_map_str;
}
$flat_networks = ['physnet-ironic']
neutron_plugin_ml2 {
'ml2_type_flat/flat_networks': value => join($flat_networks, ',');
}
service { 'neutron-plugin-openvswitch-agent':
ensure => 'running',
enable => true,
}
Neutron_plugin_ml2<||> ~> Service['neutron-plugin-openvswitch-agent']
Neutron_agent_ovs<||> ~> Service['neutron-plugin-openvswitch-agent']

View File

@ -1,49 +0,0 @@
notice('MODULAR: ironic/network-physnets.pp')
$network_scheme = hiera('network_scheme', {})
prepare_network_config($network_scheme)
$neutron_config = hiera_hash('quantum_settings')
$pnets = $neutron_config['L2']['phys_nets']
$baremetal_network = get_network_role_property('ironic/baremetal', 'network')
$nameservers = $neutron_config['predefined_networks']['net04']['L3']['nameservers']
$ironic_hash = hiera_hash('fuel-plugin-ironic', {})
$baremetal_L3_allocation_pool = $ironic_hash['l3_allocation_pool']
$baremetal_L3_gateway = $ironic_hash['l3_gateway']
# Physnets
###############################
if $pnets['physnet1'] {
$physnet1 = "physnet1:${pnets['physnet1']['bridge']}"
}
if $pnets['physnet2'] {
$physnet2 = "physnet2:${pnets['physnet2']['bridge']}"
}
$physnet_ironic = "physnet-ironic:br-ironic"
$physnets_array = [$physnet1, $physnet2, $physnet_ironic]
$bridge_mappings = delete_undef_values($physnets_array)
$br_map_str = join($bridge_mappings, ',')
neutron_agent_ovs {
'ovs/bridge_mappings': value => $br_map_str;
}
$flat_networks = ['physnet-ironic']
neutron_plugin_ml2 {
'ml2_type_flat/flat_networks': value => join($flat_networks, ',');
}
service { 'p_neutron-plugin-openvswitch-agent':
ensure => 'running',
enable => true,
provider => 'pacemaker',
}
service { 'p_neutron-dhcp-agent':
ensure => 'running',
enable => true,
provider => 'pacemaker',
}
Neutron_plugin_ml2<||> ~> Service['p_neutron-plugin-openvswitch-agent'] ~> Service['p_neutron-dhcp-agent']
Neutron_agent_ovs<||> ~> Service['p_neutron-plugin-openvswitch-agent'] ~> Service['p_neutron-dhcp-agent']

View File

@ -1,74 +0,0 @@
notice('MODULAR: ironic/vips.pp')
$network_scheme = hiera('network_scheme', {})
prepare_network_config($network_scheme)
$network_metadata = hiera_hash('network_metadata', {})
$neutron_config = hiera_hash('quantum_settings')
$pnets = $neutron_config['L2']['phys_nets']
$baremetal_vip = $network_metadata['vips']['baremetal']['ipaddr']
$baremetal_int = get_network_role_property('ironic/baremetal', 'interface')
$baremetal_ipaddr = get_network_role_property('ironic/baremetal', 'ipaddr')
$baremetal_netmask = get_network_role_property('ironic/baremetal', 'netmask')
$baremetal_network = get_network_role_property('ironic/baremetal', 'network')
$nameservers = $neutron_config['predefined_networks']['net04']['L3']['nameservers']
$ironic_hash = hiera_hash('fuel-plugin-ironic', {})
$baremetal_L3_allocation_pool = $ironic_hash['l3_allocation_pool']
$baremetal_L3_gateway = $ironic_hash['l3_gateway']
# Firewall
###############################
firewallchain { 'baremetal:filter:IPv4':
ensure => present,
} ->
firewall { '100 allow ping from VIP':
chain => 'baremetal',
source => $baremetal_vip,
destination => $baremetal_ipaddr,
proto => 'icmp',
icmp => 'echo-request',
action => 'accept',
} ->
firewall { '999 drop all':
chain => 'baremetal',
action => 'drop',
proto => 'all',
} ->
firewall {'00 baremetal-filter ':
proto => 'all',
iniface => $baremetal_int,
jump => 'baremetal',
require => Class['openstack::firewall'],
}
class { 'openstack::firewall':}
# VIP
###############################
$ns_iptables_start_rules = "iptables -A INPUT -i baremetal-ns -s ${baremetal_network} -d ${baremetal_vip} -p tcp -m multiport --dports 6385,8080 -m state --state NEW -j ACCEPT; iptables -A INPUT -i baremetal-ns -s ${baremetal_network} -d ${baremetal_vip} -m state --state ESTABLISHED,RELATED -j ACCEPT; iptables -A INPUT -i baremetal-ns -j DROP"
$ns_iptables_stop_rules = "iptables -D INPUT -i baremetal-ns -s ${baremetal_network} -d ${baremetal_vip} -p tcp -m multiport --dports 6385,8080 -m state --state NEW -j ACCEPT; iptables -D INPUT -i baremetal-ns -s ${baremetal_network} -d ${baremetal_vip} -m state --state ESTABLISHED,RELATED -j ACCEPT; iptables -D INPUT -i baremetal-ns -j DROP"
$baremetal_vip_data = {
namespace => 'haproxy',
nic => $baremetal_int,
base_veth => 'baremetal-base',
ns_veth => 'baremetal-ns',
ip => $baremetal_vip,
cidr_netmask => netmask_to_cidr($baremetal_netmask),
gateway => 'none',
gateway_metric => '0',
bridge => $baremetal_int,
ns_iptables_start_rules => $ns_iptables_start_rules,
ns_iptables_stop_rules => $ns_iptables_stop_rules,
iptables_comment => 'baremetal-filter',
}
cluster::virtual_ip { 'baremetal' :
vip => $baremetal_vip_data,
}
# Order
###############################
Firewall<||> -> Cluster::Virtual_ip<||>

View File

@ -1,14 +0,0 @@
fixtures:
repositories:
'inifile': 'git://github.com/puppetlabs/puppetlabs-inifile'
'concat':
'repo': 'git://github.com/puppetlabs/puppetlabs-concat.git'
'ref': '1.2.1'
'keystone': 'git://github.com/openstack/puppet-keystone.git'
'mysql': 'git://github.com/puppetlabs/puppetlabs-mysql.git'
'openstacklib': 'git://github.com/openstack/puppet-openstacklib.git'
'postgresql': 'git://github.com/puppetlabs/puppet-postgresql.git'
'stdlib': 'git://github.com/puppetlabs/puppetlabs-stdlib.git'
'vcsrepo': 'git://github.com/puppetlabs/puppetlabs-vcsrepo.git'
symlinks:
'ironic': "#{source_dir}"

View File

@ -1,5 +0,0 @@
*.swp
spec/fixtures/modules/*
spec/fixtures/manifests/site.pp
Gemfile.lock
.vendor

View File

@ -1,4 +0,0 @@
[gerrit]
host=review.openstack.org
port=29418
project=openstack/puppet-ironic.git

View File

@ -1,4 +0,0 @@
##2015-07-08 - 6.0.0
###Summary
- Initial release of the puppet-ironic module

View File

@ -1,30 +0,0 @@
source 'https://rubygems.org'
group :development, :test do
gem 'puppetlabs_spec_helper', :require => false
gem 'rspec-puppet', '~> 2.1.0', :require => false
gem 'metadata-json-lint'
gem 'puppet-lint-absolute_classname-check'
gem 'puppet-lint-absolute_template_path'
gem 'puppet-lint-trailing_newline-check'
# Puppet 4.x related lint checks
gem 'puppet-lint-unquoted_string-check'
gem 'puppet-lint-leading_zero-check'
gem 'puppet-lint-variable_contains_upcase'
gem 'puppet-lint-numericvariable'
gem 'beaker-rspec', :require => false
gem 'beaker-puppet_install_helper', :require => false
gem 'json'
gem 'webmock'
end
if puppetversion = ENV['PUPPET_GEM_VERSION']
gem 'puppet', puppetversion, :require => false
else
gem 'puppet', :require => false
end
# vim:ft=ruby

View File

@ -1,176 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

View File

@ -1,105 +0,0 @@
puppet-ironic
=============
6.0.0 - 2015.1 - Kilo
#### Table of Contents
1. [Overview - What is the ironic module?](#overview)
2. [Module Description - What does the module do?](#module-description)
3. [Setup - The basics of getting started with ironic](#setup)
4. [Implementation - An under-the-hood peek at what the module is doing](#implementation)
5. [Limitations - OS compatibility, etc.](#limitations)
6. [Development - Guide for contributing to the module](#development)
7. [Contributors - Those with commits](#contributors)
Overview
--------
The ironic module is a part of [OpenStack](https://github.com/openstack), an effort by the Openstack infrastructure team to provide continuous integration testing and code review for Openstack and Openstack community projects as part of the core software. The module itself is used to flexibly configure and manage the baremetal service for Openstack.
Module Description
------------------
Setup
-----
**What the ironic module affects:**
* [Ironic](https://wiki.openstack.org/wiki/Ironic), the baremetal service for Openstack.
### Installing Ironic
puppet module install openstack/ironic
### Beginning with ironic
To utilize the ironic module's functionality you will need to declare multiple resources.
The following is a modified excerpt from the [openstack module](httpd://github.com/stackforge/puppet-openstack).
This is not an exhaustive list of all the components needed. We recommend that you consult and understand the
[openstack module](https://github.com/stackforge/puppet-openstack) and the [core openstack](http://docs.openstack.org)
documentation to assist you in understanding the available deployment options.
```puppet
# enable Ironic resources
class { '::ironic':
rabbit_userid => 'ironic',
rabbit_password => 'an_even_bigger_secret',
rabbit_host => '127.0.0.1',
database_connection => 'mysql://ironic:a_big_secret@127.0.0.1/ironic?charset=utf8',
}
class { '::ironic::db::mysql':
password => 'a_big_secret',
}
class { '::ironic::keystone::auth':
password => 'a_big_secret',
}
class { '::ironic::client': }
class { '::ironic::conductor': }
class { '::ironic::api':
admin_password => 'a_big_secret',
}
class { '::ironic::drivers::ipmi': }
```
Examples of usage also can be found in the *examples* directory.
Implementation
--------------
### puppet-ironic
puppet-ironic is a combination of Puppet manifest and ruby code to delivery configuration and extra functionality through types and providers.
Limitations
-----------
Beaker-Rspec
------------
This module has beaker-rspec tests
To run:
``shell
bundle install
bundle exec rspec spec/acceptance
``
Development
-----------
Developer documentation for the entire puppet-openstack project.
* https://wiki.openstack.org/wiki/Puppet-openstack#Developer_documentation
Contributors
------------
* https://github.com/openstack/puppet-ironic/graphs/contributors

View File

@ -1,9 +0,0 @@
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
PuppetLint.configuration.fail_on_warnings = true
PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.send('disable_class_parameter_defaults')
task(:default).clear
task :default => [:spec, :lint]

View File

@ -1,119 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Deploy Ironic
#
$db_host = 'db'
$db_username = 'ironic'
$db_name = 'ironic'
$db_password = 'password'
$rabbit_user = 'ironic'
$rabbit_password = 'ironic'
$rabbit_vhost = '/'
$rabbit_hosts = ['rabbitmq:5672']
$rabbit_port = '5672'
$glance_api_servers = 'glance:9292'
$deploy_kernel = 'glance://deploy_kernel_uuid'
$deploy_ramdisk = 'glance://deploy_ramdisk_uuid'
$baremetal_json_hosts = '
"ironic-bm-test.bifrost.example": {
"ansible_ssh_host": "1.1.1.1",
"uuid": "11111111-1111-1111-1111-111111111111",
"driver_info": {
"power": {
"ipmi_address": "10.0.0.1",
"ipmi_username": "admin",
"ipmi_password": "pass"
},
},
"nics": [
{
"mac": "ff:ff:ff:ff:ff:ff"
}
],
"driver": "agent_ipmitool",
"ipv4_address": "1.1.1.1",
"properties": {
"cpu_arch": "x86_64",
"ram": null,
"disk_size": null,
"cpus": null
},
"name": "ironic-bm-test.bifrost.example"
}
'
node 'db' {
class { '::mysql::server':
config_hash => {
'bind_address' => '0.0.0.0',
},
}
class { '::mysql::ruby': }
class { '::ironic::db::mysql':
password => $db_password,
dbname => $db_name,
user => $db_username,
host => $clientcert,
allowed_hosts => ['controller'],
}
}
node controller {
class { '::ironic':
db_password => $db_password,
db_name => $db_name,
db_user => $db_username,
db_host => $db_host,
rabbit_password => $rabbit_password,
rabbit_userid => $rabbit_user,
rabbit_virtual_host => $rabbit_vhost,
rabbit_hosts => $rabbit_hosts,
glance_api_servers => $glance_api_servers,
}
class { '::ironic::api': }
class { '::ironic::conductor': }
class { '::ironic::drivers::ipmi': }
class { '::ironic::drivers::pxe':
deploy_kernel => $deploy_kernel,
deploy_ramdisk => $deploy_ramdisk,
}
}
node bifrost-controller {
class { '::ironic::bifrost':
network_interface => 'eth1',
ironic_db_password => 'changeme',
mysql_password => 'changemetoo',
baremetal_json_hosts => $baremetal_json_hosts,
}
}

View File

@ -1,150 +0,0 @@
require 'csv'
require 'puppet/util/inifile'
class Puppet::Provider::Ironic < Puppet::Provider
def self.conf_filename
'/etc/ironic/ironic.conf'
end
def self.withenv(hash, &block)
saved = ENV.to_hash
hash.each do |name, val|
ENV[name.to_s] = val
end
yield
ensure
ENV.clear
saved.each do |name, val|
ENV[name] = val
end
end
def self.ironic_credentials
@ironic_credentials ||= get_ironic_credentials
end
def self.get_ironic_credentials
auth_keys = ['auth_host', 'auth_port', 'auth_protocol',
'admin_tenant_name', 'admin_user', 'admin_password']
conf = ironic_conf
if conf and conf['keystone_authtoken'] and
auth_keys.all?{|k| !conf['keystone_authtoken'][k].nil?}
return Hash[ auth_keys.map \
{ |k| [k, conf['keystone_authtoken'][k].strip] } ]
else
raise(Puppet::Error, "File: #{conf_filename} does not contain all \
required sections. Ironic types will not work if ironic is not \
correctly configured.")
end
end
def ironic_credentials
self.class.ironic_credentials
end
def self.auth_endpoint
@auth_endpoint ||= get_auth_endpoint
end
def self.get_auth_endpoint
q = ironic_credentials
"#{q['auth_protocol']}://#{q['auth_host']}:#{q['auth_port']}/v2.0/"
end
def self.ironic_conf
return @ironic_conf if @ironic_conf
@ironic_conf = Puppet::Util::IniConfig::File.new
@ironic_conf.read(conf_filename)
@ironic_conf
end
def self.auth_ironic(*args)
q = ironic_credentials
authenv = {
:OS_AUTH_URL => self.auth_endpoint,
:OS_USERNAME => q['admin_user'],
:OS_TENANT_NAME => q['admin_tenant_name'],
:OS_PASSWORD => q['admin_password']
}
begin
withenv authenv do
ironic(args)
end
rescue Exception => e
if (e.message =~ /\[Errno 111\] Connection refused/) or
(e.message =~ /\(HTTP 400\)/)
sleep 10
withenv authenv do
ironic(args)
end
else
raise(e)
end
end
end
def auth_ironic(*args)
self.class.auth_ironic(args)
end
def self.reset
@ironic_conf = nil
@ironic_credentials = nil
end
def self.list_ironic_resources(type)
ids = []
list = auth_ironic("#{type}-list", '--format=csv',
'--column=id', '--quote=none')
(list.split("\n")[1..-1] || []).compact.collect do |line|
ids << line.strip
end
return ids
end
def self.get_ironic_resource_attrs(type, id)
attrs = {}
net = auth_ironic("#{type}-show", '--format=shell', id)
last_key = nil
(net.split("\n") || []).compact.collect do |line|
if line.include? '='
k, v = line.split('=', 2)
attrs[k] = v.gsub(/\A"|"\Z/, '')
last_key = k
else
# Handle the case of a list of values
v = line.gsub(/\A"|"\Z/, '')
attrs[last_key] = [attrs[last_key], v]
end
end
return attrs
end
def self.get_tenant_id(catalog, name)
instance_type = 'keystone_tenant'
instance = catalog.resource("#{instance_type.capitalize!}[#{name}]")
if ! instance
instance = Puppet::Type.type(instance_type).instances.find do |i|
i.provider.name == name
end
end
if instance
return instance.provider.id
else
fail("Unable to find #{instance_type} for name #{name}")
end
end
def self.parse_creation_output(data)
hash = {}
data.split("\n").compact.each do |line|
if line.include? '='
hash[line.split('=').first] = line.split('=', 2)[1].gsub(/\A"|"\Z/, '')
end
end
hash
end
end

View File

@ -1,27 +0,0 @@
Puppet::Type.type(:ironic_config).provide(
:ini_setting,
:parent => Puppet::Type.type(:ini_setting).provider(:ruby)
) do
def section
resource[:name].split('/', 2).first
end
def setting
resource[:name].split('/', 2).last
end
def separator
'='
end
def self.file_path
'/etc/ironic/ironic.conf'
end
# added for backwards compatibility with older versions of inifile
def file_path
self.class.file_path
end
end

View File

@ -1,150 +0,0 @@
require 'rubygems'
require 'net/http'
require 'net/https'
require 'json'
require 'puppet/util/inifile'
class KeystoneError < Puppet::Error
end
class KeystoneConnectionError < KeystoneError
end
class KeystoneAPIError < KeystoneError
end
RETRY_COUNT = 10
RETRY_SLEEP = 3
def handle_request(req, url)
begin
use_ssl = url.scheme == "https" ? true : false
http = Net::HTTP.start(url.hostname, url.port, {:use_ssl => use_ssl})
res = http.request(req)
if res.code != '200'
raise KeystoneAPIError, "Received error response from Keystone server at #{url}: #{res.message}"
end
rescue Errno::ECONNREFUSED => detail
raise KeystoneConnectionError, "Failed to connect to Keystone server at #{url}: #{detail}"
rescue SocketError => detail
raise KeystoneConnectionError, "Failed to connect to Keystone server at #{url}: #{detail}"
end
res
end
def keystone_v2_authenticate(auth_url,
username,
password,
tenantId=nil,
tenantName=nil)
post_args = {
'auth' => {
'passwordCredentials' => {
'username' => username,
'password' => password
},
}}
if tenantId
post_args['auth']['tenantId'] = tenantId
end
if tenantName
post_args['auth']['tenantName'] = tenantName
end
url = URI.parse("#{auth_url}/tokens")
req = Net::HTTP::Post.new url.path
req['content-type'] = 'application/json'
req.body = post_args.to_json
res = handle_request(req, url)
data = JSON.parse res.body
return data['access']['token']['id']
end
def glance_images(glance_url, token)
url = URI.parse("#{glance_url}/images")
req = Net::HTTP::Get.new url.path
req['content-type'] = 'application/json'
req['x-auth-token'] = token
res = handle_request(req, url)
data = JSON.parse res.body
data['images']
end
Puppet::Type.type(:ironic_images_setter).provide(:ruby) do
@ironic_images = nil
def authenticate
keystone_v2_authenticate(
@resource[:auth_url],
@resource[:auth_username],
@resource[:auth_password],
nil,
@resource[:auth_tenant_name])
end
def find_image_by_name(images, name)
found_images = images.select{|image| image['name'] == name}
if found_images.length == 1
return found_images[0]['id']
elsif found_images.length == 0
raise KeystoneAPIError, "Image with name '#{name}' not found."
elsif found_images.length > 1
raise KeystoneAPIError, "Found multiple matches for name: '#{name}'"
end
end
def exists?
ini_file = Puppet::Util::IniConfig::File.new
ini_file.read("/etc/ironic/ironic.conf")
ironic_images.each do |setting, id|
if ! ( ini_file['fuel'] && ini_file['fuel'][setting] && ini_file['fuel'][setting] == id)
return nil
end
end
end
def create
config
end
def ironic_images
@ironic_images ||= get_ironic_images
end
def get_ironic_images
token = authenticate
RETRY_COUNT.times do |n|
begin
all_images = glance_images(@resource[:glance_url], token)
rescue => e
debug "Request failed: '#{e.message}' Retry: '#{n}'"
if n == RETRY_COUNT - 1
raise KeystoneAPIError, 'Unable to get images.'
end
sleep RETRY_SLEEP
next
end
ironic_images = Hash.new
ironic_images['deploy_kernel'] = find_image_by_name(all_images, 'ironic-deploy-linux')
ironic_images['deploy_ramdisk'] = find_image_by_name(all_images, 'ironic-deploy-initramfs')
ironic_images['deploy_squashfs'] = find_image_by_name(all_images, 'ironic-deploy-squashfs')
return ironic_images
end
end
def config
ironic_images.each do |setting, id|
Puppet::Type.type(:ironic_config).new(
{:name => "fuel/#{setting}", :value => id}
).provider.create
end
end
end

View File

@ -1,47 +0,0 @@
Puppet::Type.newtype(:ironic_config) do
ensurable
newparam(:name, :namevar => true) do
desc 'Section/setting name to manage from /etc/ironic/ironic.conf'
newvalues(/\S+\/\S+/)
end
newproperty(:value) do
desc 'The value of the setting to be defined.'
munge do |value|
value = value.to_s.strip
value.capitalize! if value =~ /^(true|false)$/i
value
end
def is_to_s( currentvalue )
if resource.secret?
return '[old secret redacted]'
else
return currentvalue
end
end
def should_to_s( newvalue )
if resource.secret?
return '[new secret redacted]'
else
return newvalue
end
end
end
newparam(:secret, :boolean => true) do
desc 'Whether to hide the value from Puppet logs. Defaults to `false`.'
newvalues(:true, :false)
defaultto false
end
autorequire(:package) do
'ironic-common'
end
end

View File

@ -1,31 +0,0 @@
Puppet::Type.newtype(:ironic_images_setter) do
ensurable
newparam(:name, :namevar => true) do
desc 'The name of the setting to update'
end
newparam(:auth_url) do
desc 'The Keystone endpoint URL'
defaultto 'http://localhost:35357/v2.0'
end
newparam(:auth_username) do
desc 'Username with which to authenticate'
defaultto 'admin'
end
newparam(:auth_password) do
desc 'Password with which to authenticate'
end
newparam(:auth_tenant_name) do
desc 'Tenant name with which to authenticate'
defaultto 'admin'
end
newparam(:glance_url) do
desc 'Glance endpoint'
end
end

View File

@ -1,182 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Configure the API service in Ironic
#
# === Parameters
#
# [*package_ensure*]
# (optional) Control the ensure parameter for the package ressource.
# Defaults to 'present'.
#
# [*enabled*]
# (optional) Define if the service must be enabled or not.
# Defaults to true.
#
# [*host_ip*]
# (optional) The listen IP for the Ironic API server.
# Should be an valid IP address
# Defaults to '0.0.0.0'.
#
# [*port*]
# (optional) The port for the Ironic API server.
# Should be an valid port
# Defaults to '0.0.0.0'.
#
# [*max_limit*]
# (optional) The maximum number of items returned in a single response
# from a collection resource.
# Should be an valid interger
# Defaults to '1000'.
#
# [*auth_host*]
# (optional) The IP of the server running keystone
# Defaults to '127.0.0.1'
#
# [*auth_port*]
# (optional) The port to use when authenticating against Keystone
# Defaults to 35357
#
# [*auth_protocol*]
# (optional) The protocol to use when authenticating against Keystone
# Defaults to 'http'
#
# [*auth_uri*]
# (optional) The uri of a Keystone service to authenticate against
# Defaults to false
#
# [*auth_admin_prefix*]
# (optional) Prefix to prepend at the beginning of the keystone path
# Defaults to false
#
# [*auth_version*]
# (optional) API version of the admin Identity API endpoint
# for example, use 'v3.0' for the keystone version 3.0 api
# Defaults to false
#
# [*admin_tenant_name*]
# (optional) The name of the tenant to create in keystone for use by the ironic services
# Defaults to 'services'
#
# [*admin_user*]
# (optional) The name of the user to create in keystone for use by the ironic services
# Defaults to 'ironic'
#
# [*neutron_url*]
# (optional) The Neutron URL to be used for requests from ironic
# Defaults to false
#
# [*admin_password*]
# (required) The password to set for the ironic admin user in keystone
#
class ironic::api (
$package_ensure = 'present',
$enabled = true,
$host_ip = '0.0.0.0',
$port = '6385',
$max_limit = '1000',
$auth_host = '127.0.0.1',
$auth_port = '35357',
$auth_protocol = 'http',
$auth_uri = false,
$auth_admin_prefix = false,
$auth_version = false,
$admin_tenant_name = 'services',
$admin_user = 'ironic',
$neutron_url = false,
$admin_password,
) {
include ::ironic::params
include ::ironic::policy
Ironic_config<||> ~> Service['ironic-api']
Class['ironic::policy'] ~> Service['ironic-api']
# Configure ironic.conf
ironic_config {
'api/host_ip': value => $host_ip;
'api/port': value => $port;
'api/max_limit': value => $max_limit;
}
# Install package
if $::ironic::params::api_package {
Package['ironic-api'] -> Class['ironic::policy']
Package['ironic-api'] -> Service['ironic-api']
package { 'ironic-api':
ensure => $package_ensure,
name => $::ironic::params::api_package,
tag => ['openstack', 'ironic-package'],
}
}
if $enabled {
$ensure = 'running'
} else {
$ensure = 'stopped'
}
# Manage service
service { 'ironic-api':
ensure => $ensure,
name => $::ironic::params::api_service,
enable => $enabled,
hasstatus => true,
tag => 'ironic-service',
}
if $neutron_url {
ironic_config { 'neutron/url': value => $neutron_url; }
} else {
ironic_config { 'neutron/url': value => "${auth_protocol}://${auth_host}:9696/"; }
}
if $auth_uri {
ironic_config { 'keystone_authtoken/auth_uri': value => $auth_uri; }
} else {
ironic_config { 'keystone_authtoken/auth_uri': value => "${auth_protocol}://${auth_host}:5000/"; }
}
if $auth_version {
ironic_config { 'keystone_authtoken/auth_version': value => $auth_version; }
} else {
ironic_config { 'keystone_authtoken/auth_version': ensure => absent; }
}
ironic_config {
'keystone_authtoken/auth_host': value => $auth_host;
'keystone_authtoken/auth_port': value => $auth_port;
'keystone_authtoken/auth_protocol': value => $auth_protocol;
'keystone_authtoken/admin_tenant_name': value => $admin_tenant_name;
'keystone_authtoken/admin_user': value => $admin_user;
'keystone_authtoken/admin_password': value => $admin_password, secret => true;
}
if $auth_admin_prefix {
validate_re($auth_admin_prefix, '^(/.+[^/])?$')
ironic_config {
'keystone_authtoken/auth_admin_prefix': value => $auth_admin_prefix;
}
} else {
ironic_config {
'keystone_authtoken/auth_admin_prefix': ensure => absent;
}
}
}

View File

@ -1,202 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# == Class: ironic::bifrost
#
# Installs and configures Bifrost
# Bifrost is a set of Ansible playbooks that automates the task of deploying a
# base image onto a set of known hardware using Ironic. It provides modular
# utility for one-off operating system deployment with as few operational requirements
# as reasonably possible.
# Bifrost also allows to install Ironic in a stand-alone fashion. In this kind of setup,
# neither Keystone nor Neutron is installed, and dnsmasq is used to provide PXE booting.
#
# [*ironic_db_password*]
# (required) The Ironic DB password
#
# [*mysql_password*]
# (required) The mysql server password
#
# [*baremetal_json_hosts*]
# (required) Baremetal hosts in JSON format, will be included in baremetal.json
#
# [*git_source_repo*]
# (optional) Git repository location for pulling Bifrost
# Defaults to 'https://git.openstack.org/openstack/bifrost'
#
# [*revision*]
# (optional) The branch or commit to checkout on Bifrost repository
# Defaults to 'master'
#
# [*ensure*]
# (optional) Ensure value for cloning the Bifrost repository.
# This is a pass-thru variable for vcsrepo, acceptable values are
# present/bare/absent/latest
# Typically, you may want to set this value to either present or absent and use
# revision for setting the branch or commit to clone.
# Defaults to 'present'
#
# [*revision*]
# (optional) The branch or commit to checkout on Bifrost repository
# Defaults to 'master'
#
# [*git_dest_repo_folder*]
# (optional) Folder to clone the Bifrost git repository
# Defaults to '/opt/stack/bifrost'
#
# [*ironic_url*]
# (optional) The URL of the Ironic server
# Defaults to '"http://localhost:6385"'
#
# [*network_interface*]
# (optional) The network interface DHCP will serve requests on
# Defaults to '"virbr0"'
#
# [*testing*]
# (optional) If true, Ironic will provision libvirt and VMs instead of baremetal
# Defaults to 'false'
#
# [*testing_user*]
# (optional) VM default user in case testing is enabled
# Defaults to 'ubuntu'
#
# [*http_boot_folder*]
# (optional) gPXE folder location for HTTP PXE boot
# Defaults to '/httpboot'
#
# [*nginx_port*]
# (optional) NGINX HTTP port
# Defaults to 8080
# [*ssh_public_key_path*]
# (optional) SSH public key location, this will be injected in provisioned servers
# Defaults to '"{{ ansible_env.HOME }}/.ssh/id_rsa.pub"'
#
# [*deploy_kernel*]
# (optional) Kernel to PXE boot from
# Defaults to '"{{http_boot_folder}}/coreos_production_pxe.vmlinuz"'
#
# [*deploy_ramdisk*]
# (optional) Ramdisk to load after kernel boot
# Defaults to '"{{http_boot_folder}}/coreos_production_pxe_image-oem.cpio.gz"'
#
# [*deploy_kernel_url*]
# (optional) Kernel URL
# Defaults to '"http://{{ hostvars[inventory_hostname][\'ansible_\' + network_interface][\'ipv4\'][\'address\'] }}:{{nginx_port}}/coreos_production_pxe.vmlinuz"'
#
# [*deploy_ramdisk_url*]
# (optional) Ramdisk URL
# Defaults to '"http://{{ hostvars[inventory_hostname][\'ansible_\' + network_interface][\'ipv4\'][\'address\'] }}:{{nginx_port}}/coreos_production_pxe_image-oem.cpio.gz"'
#
# [*deploy_image_filename*]
# (optional) Deploy image filename
# Defaults to '"deployment_image.qcow2"'
#
# [*deploy_image*]
# (optional) URL for the deployment image
# Defaults to '"{{http_boot_folder}}/{{deploy_image_filename}}"'
#
# [*create_image_via_dib*]
# (optional) Flag to enable/disable image creation with diskimage-builder
# Defaults to 'true'
#
# [*transform_boot_image*]
# (optional) Flag to prepend a partition image with boot sector and partition table
# Defaults to 'false'
#
# [*node_default_network_interface*]
# (optional) Default network interface to configure with configdrive settings
# Defaults to 'eth0'
#
# [*ipv4_subnet_mask*]
# (optional) Subnet mask for configured NIC
# Defaults to '255.255.255.0'
#
# [*ipv4_gateway*]
# (optional) Gateway for configured NIC
# Defaults to '192.168.1.1'
#
# [*ipv4_nameserver*]
# (optional) Nameserver for DNS configuration
# Defaults to '8.8.8.8'
#
# [*network_mtu*]
# (optional) MTU for configured NIC
# Defaults to '1500'
#
# [*dhcp_pool_start*]
# (optional) Dnsmasq DHCP pool start
# Defaults to '192.168.1.200'
#
# [*dhcp_pool_end*]
# (optional) Dnsmasq DHCP pool end
# Defaults to '192.168.1.250'
#
# [*ipmi_bridging*]
# (optional) Flag to enable/disable IPMI bridging
# Defaults to 'no'
class ironic::bifrost (
$ironic_db_password,
$mysql_password,
$baremetal_json_hosts,
$git_source_repo = 'https://git.openstack.org/openstack/bifrost',
$ensure = present,
$revision = 'master',
$git_dest_repo_folder = '/opt/stack/bifrost',
$ironic_url = '"http://localhost:6385/"',
$network_interface = '"virbr0"',
$testing = false,
$testing_user = 'ubuntu',
$http_boot_folder = '/httpboot',
$nginx_port = 8080,
$ssh_public_key_path = '"{{ ansible_env.HOME }}/.ssh/id_rsa.pub"',
$deploy_kernel = '"{{http_boot_folder}}/coreos_production_pxe.vmlinuz"',
$deploy_ramdisk = '"{{http_boot_folder}}/coreos_production_pxe_image-oem.cpio.gz"',
$deploy_kernel_url = '"http://{{ hostvars[inventory_hostname][\'ansible_\' + network_interface][\'ipv4\'][\'address\'] }}:{{nginx_port}}/coreos_production_pxe.vmlinuz"',
$deploy_ramdisk_url = '"http://{{ hostvars[inventory_hostname][\'ansible_\' + network_interface][\'ipv4\'][\'address\'] }}:{{nginx_port}}/coreos_production_pxe_image-oem.cpio.gz"',
$deploy_image_filename = '"deployment_image.qcow2"',
$deploy_image = '"{{http_boot_folder}}/{{deploy_image_filename}}"',
$create_image_via_dib = true,
$transform_boot_image = false,
$node_default_network_interface = 'eth0',
$ipv4_subnet_mask = '255.255.255.0',
$ipv4_gateway = '192.168.1.1',
$ipv4_nameserver = '8.8.8.8',
$network_mtu = '1500',
$dhcp_pool_start = '192.168.1.200',
$dhcp_pool_end = '192.168.1.250',
$ipmi_bridging = 'no',
) {
vcsrepo { $git_dest_repo_folder:
ensure => $ensure,
provider => git,
revision => $revision,
source => $git_source_repo,
}
file { "${git_dest_repo_folder}/playbooks/inventory/group_vars/all":
ensure => present,
content => template('ironic/group_vars_all.erb'),
require => Vcsrepo[$git_dest_repo_folder],
}
file { "${git_dest_repo_folder}/baremetal.json":
ensure => present,
content => template('ironic/baremetal.json.erb'),
require => Vcsrepo[$git_dest_repo_folder],
}
}

View File

@ -1,41 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# ironic::client
#
# Manages the ironic client package on systems
#
# === Parameters:
#
# [*package_ensure*]
# (optional) The state of the package
# Defaults to present
#
class ironic::client (
$package_ensure = present
) {
include ::ironic::params
package { 'python-ironicclient':
ensure => $package_ensure,
name => $::ironic::params::client_package,
tag => 'openstack',
}
}

View File

@ -1,83 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Configure the conductor service in Ironic
#
# === Parameters
#
# [*package_ensure*]
# (optional) Control the ensure parameter for the package ressource.
# Defaults to 'present'.
#
# [*enabled*]
# (optional) Define if the service must be enabled or not.
# Defaults to true.
#
# [*max_time_interval*]
# (optional) Maximum time, in seconds, since the last check-in of a conductor.
# Should be an interger value
# Defaults to '120'.
#
# [*force_power_state_during_sync*]
# (optional) Should the hardware power state be set to the state recorded in
# the database (True) or should the database be updated based on the hardware
# state (False).
# Defaults to true.
#
class ironic::conductor (
$package_ensure = 'present',
$enabled = true,
$max_time_interval = '120',
$force_power_state_during_sync = true,
) {
include ::ironic::params
Ironic_config<||> ~> Service['ironic-conductor']
# Configure ironic.conf
ironic_config {
'conductor/max_time_interval': value => $max_time_interval;
'conductor/force_power_state_during_sync': value => $force_power_state_during_sync;
}
# Install package
if $::ironic::params::conductor_package {
Package['ironic-conductor'] -> Service['ironic-conductor']
package { 'ironic-conductor':
ensure => $package_ensure,
name => $::ironic::params::conductor_package,
tag => ['openstack', 'ironic-package'],
}
}
if $enabled {
$ensure = 'running'
} else {
$ensure = 'stopped'
}
# Manage service
service { 'ironic-conductor':
ensure => $ensure,
name => $::ironic::params::conductor_service,
enable => $enabled,
hasstatus => true,
tag => 'ironic-service',
}
}

View File

@ -1,30 +0,0 @@
# == Class: ironic::config
#
# This class is used to manage arbitrary Ironic configurations.
#
# === Parameters
#
# [*ironic_config*]
# (optional) Allow configuration of arbitrary Ironic configurations.
# The value is an hash of ironic_config resources. Example:
# { 'DEFAULT/foo' => { value => 'fooValue'},
# 'DEFAULT/bar' => { value => 'barValue'}
# }
# In yaml format, Example:
# ironic_config:
# DEFAULT/foo:
# value: fooValue
# DEFAULT/bar:
# value: barValue
#
# NOTE: The configuration MUST NOT be already handled by this module
# or Puppet catalog compilation will fail with duplicate resources.
#
class ironic::config (
$ironic_config = {},
) {
validate_hash($ironic_config)
create_resources('ironic_config', $ironic_config)
}

View File

@ -1,77 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# ironic::db::mysql
#
# [*password*]
# Password to use for the nova user
#
# [*dbname*]
# (optional) The name of the database
# Defaults to 'nova'
#
# [*user*]
# (optional) The mysql user to create
# Defaults to 'nova'
#
# [*host*]
# (optional) The IP address of the mysql server
# Defaults to '127.0.0.1'
#
# [*charset*]
# (optional) The charset to use for the nova database
# Defaults to 'utf8'
#
# [*collate*]
# (optional) The collate to use for the nova database
# Defaults to 'utf8_general_ci'
#
# [*allowed_hosts*]
# (optional) Additional hosts that are allowed to access this DB
# Defaults to undef
#
# [*cluster_id*]
# (optional) Deprecated. Does nothing
class ironic::db::mysql (
$password,
$dbname = 'ironic',
$user = 'ironic',
$host = '127.0.0.1',
$allowed_hosts = undef,
$charset = 'utf8',
$collate = 'utf8_general_ci',
$cluster_id = undef,
) {
if $cluster_id {
warning('The cluster_id parameter is deprecated and has no effect.')
}
::openstacklib::db::mysql { 'ironic':
user => $user,
password_hash => mysql_password($password),
dbname => $dbname,
host => $host,
charset => $charset,
collate => $collate,
allowed_hosts => $allowed_hosts,
}
::Openstacklib::Db::Mysql['ironic'] ~> Exec<| title == 'ironic-dbsync' |>
}

View File

@ -1,47 +0,0 @@
# == Class: ironic::db::postgresql
#
# Class that configures postgresql for ironic
# Requires the Puppetlabs postgresql module.
#
# === Parameters
#
# [*password*]
# (Required) Password to connect to the database.
#
# [*dbname*]
# (Optional) Name of the database.
# Defaults to 'ironic'.
#
# [*user*]
# (Optional) User to connect to the database.
# Defaults to 'ironic'.
#
# [*encoding*]
# (Optional) The charset to use for the database.
# Default to undef.
#
# [*privileges*]
# (Optional) Privileges given to the database user.
# Default to 'ALL'
#
class ironic::db::postgresql(
$password,
$dbname = 'ironic',
$user = 'ironic',
$encoding = undef,
$privileges = 'ALL',
) {
Class['ironic::db::postgresql'] -> Service<| title == 'ironic' |>
::openstacklib::db::postgresql { 'ironic':
password_hash => postgresql_password($user, $password),
dbname => $dbname,
user => $user,
encoding => $encoding,
privileges => $privileges,
}
::Openstacklib::Db::Postgresql['ironic'] ~> Exec<| title == 'ironic-dbsync' |>
}

View File

@ -1,26 +0,0 @@
#
# Class to execute ironic dbsync
#
class ironic::db::sync {
include ::ironic::params
Package<| tag == 'ironic-package' |> ~> Exec['ironic-dbsync']
Exec['ironic-dbsync'] ~> Service <| tag == 'ironic-service' |>
Ironic_config<||> -> Exec['ironic-dbsync']
Ironic_config<| title == 'database/connection' |> ~> Exec['ironic-dbsync']
exec { 'ironic-dbsync':
command => $::ironic::params::dbsync_command,
path => '/usr/bin',
# Ubuntu packaging is running dbsync command as root during ironic-common
# postinstall script so when Puppet tries to run dbsync again, it fails
# because it is run with ironic user.
# This is a temporary patch until it's changed in Packaging
# https://bugs.launchpad.net/cloud-archive/+bug/1450942
user => 'root',
refreshonly => true,
logoutput => on_failure,
}
}

View File

@ -1,37 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Configure the IPMI driver in Ironic
#
# === Parameters
#
# [*retry_timeout*]
# (optional) Maximum time in seconds to retry IPMI operations.
# Should be an interger value
# Defaults to '10'.
#
class ironic::drivers::ipmi (
$retry_timeout = '10'
) {
# Configure ironic.conf
ironic_config {
'ipmi/retry_timeout': value => $retry_timeout;
}
}

View File

@ -1,110 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Configure the PXE driver in Ironic
#
# === Parameters
#
# [*deploy_kernel*]
# (optional) Default kernel image ID used in deployment phase.
# Should be an valid id
# Defaults to undef.
#
# [*deploy_ramdisk*]
# (optional) Default kernel image ID used in deployment phase.
# Should be an valid id
# Defaults to undef.
#
# [*pxe_append_params*]
# (optional) Additional append parameters for baremetal PXE boot.
# Should be valid pxe parameters
# Defaults to 'nofb nomodeset vga=normal'.
#
# [*pxe_config_template*]
# (optional) Template file for PXE configuration.
# Should be an valid template file
# Defaults to '$pybasedir/drivers/modules/pxe_config.template'.
#
# [*pxe_deploy_timeout*]
# (optional) Timeout for PXE deployments.
# Should be an valid integer
# Defaults to '0' for unlimited.
#
# [*tftp_server*]
# (optional) IP address of Ironic compute node's tftp server.
# Should be an valid IP address
# Defaults to '$my_ip'.
#
# [*tftp_root*]
# (optional) Ironic compute node's tftp root path.
# Should be an valid path
# Defaults to '/tftpboot'.
#
# [*images_path*]
# (optional) Directory where images are stored on disk.
# Should be an valid directory
# Defaults to '/tftpboot'.
#
# [*tftp_master_path*]
# (optional) Directory where master tftp images are stored on disk.
# Should be an valid directory
# Defaults to '/tftpboot/master_images'.
#
# [*instance_master_path*]
# (optional) Directory where master tftp images are stored on disk.
# Should be an valid directory
# Defaults to '/var/lib/ironic/master_images'.
#
class ironic::drivers::pxe (
$deploy_kernel = undef,
$deploy_ramdisk = undef,
$pxe_append_params = 'nofb nomodeset vga=normal',
$pxe_config_template = '$pybasedir/drivers/modules/pxe_config.template',
$pxe_deploy_timeout = '0',
$tftp_server = '$my_ip',
$tftp_root = '/tftpboot',
$images_path = '/var/lib/ironic/images/',
$tftp_master_path = '/tftpboot/master_images',
$instance_master_path = '/var/lib/ironic/master_images',
) {
# Configure ironic.conf
ironic_config {
'pxe/pxe_append_params': value => $pxe_append_params;
'pxe/pxe_config_template': value => $pxe_config_template;
'pxe/pxe_deploy_timeout': value => $pxe_deploy_timeout;
'pxe/tftp_server': value => $tftp_server;
'pxe/tftp_root': value => $tftp_root;
'pxe/images_path': value => $images_path;
'pxe/tftp_master_path': value => $tftp_master_path;
'pxe/instance_master_path': value => $instance_master_path;
}
if $deploy_kernel {
ironic_config {
'pxe/deploy_kernel': value => $deploy_kernel;
}
}
if $deploy_ramdisk {
ironic_config {
'pxe/deploy_ramdisk': value => $deploy_ramdisk;
}
}
}

View File

@ -1,402 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# == Class: ironic
#
# Installs the ironic package and configures /etc/ironic/ironic.conf
#
# === Parameters:
#
# [*enabled*]
# (required) Whether or not to enable the ironic service
# true/false
#
# [*package_ensure*]
# (optional) The state of the package
# Defaults to 'present'
#
# [*verbose*]
# (optional) Verbose logging
# Defaults to False
#
# [*debug*]
# (optional) Print debug messages in the logs
# Defaults to False
#
# [*auth_strategy*]
# (optional) Default protocol to use when connecting to glance
# Defaults to 'keystone'. 'https' is the only other valid option for SSL
#
# [*enabled_drivers*]
# (optional) Array of drivers to load during service
# initialization.
# Defaults to ['pxe_ipmitool'].
#
# [*control_exchange*]
# (optional) What RPC queue/exchange to use
# Defaults to openstack
#
# [*rpc_backend*]
# (optional) what rpc/queuing service to use
# Defaults to impl_kombu (rabbitmq)
#
# [*rabbit_host*]
# (Optional) IP or hostname of the rabbit server.
# Defaults to 'localhost'
#
# [*rabbit_port*]
# (Optional) Port of the rabbit server.
# Defaults to 5672.
#
# [*rabbit_hosts*]
# (Optional) Array of host:port (used with HA queues).
# If defined, will remove rabbit_host & rabbit_port parameters from config
# Defaults to undef.
#
# [*rabbit_user*]
# (Optional) User to connect to the rabbit server.
# Defaults to undef.
# Deprecated, use rabbit_userid instead.
#
# [*rabbit_userid*]
# (Optional) User to connect to the rabbit server.
# Defaults to 'guest'
#
# [*rabbit_password*]
# (Optional) Password to connect to the rabbit_server.
# Defaults to empty.
#
# [*rabbit_virtual_host*]
# (Optional) Virtual_host to use.
# Defaults to '/'
#
# [*rabbit_use_ssl*]
# (optional) Connect over SSL for RabbitMQ
# Defaults to false
#
# [*kombu_ssl_ca_certs*]
# (optional) SSL certification authority file (valid only if SSL enabled).
# Defaults to undef
#
# [*kombu_ssl_certfile*]
# (optional) SSL cert file (valid only if SSL enabled).
# Defaults to undef
#
# [*kombu_ssl_keyfile*]
# (optional) SSL key file (valid only if SSL enabled).
# Defaults to undef
#
# [*kombu_ssl_version*]
# (optional) SSL version to use (valid only if SSL enabled).
# Valid values are TLSv1, SSLv23 and SSLv3. SSLv2 may be
# available on some distributions.
# Defaults to 'TLSv1'
#
# [*amqp_durable_queues*]
# Use durable queues in amqp.
# (Optional) Defaults to false.
#
# [*rabbit_virtual_host*]
# (optional) Various rabbitmq settings
#
# [*rabbit_hosts*]
# (optional) array of rabbitmq servers for HA.
# A single IP address, such as a VIP, can be used for load-balancing
# multiple RabbitMQ Brokers.
# Defaults to false
#
# [*qpid_hostname*]
# [*qpid_port*]
# [*qpid_username*]
# [*qpid_password*]
# [*qpid_heartbeat*]
# [*qpid_protocol*]
# [*qpid_tcp_nodelay*]
# [*qpid_reconnect*]
# [*qpid_reconnect_timeout*]
# [*qpid_reconnect_limit*]
# [*qpid_reconnect_interval*]
# [*qpid_reconnect_interval_min*]
# [*qpid_reconnect_interval_max*]
# (optional) various QPID options
#
# [*use_syslog*]
# (optional) Use syslog for logging
# Defaults to false
#
# [*log_facility*]
# (optional) Syslog facility to receive log lines
# Defaults to LOG_USER
#
# [*database_connection*]
# (optional) Connection url for the ironic database.
# Defaults to: sqlite:////var/lib/ironic/ironic.sqlite
#
# [*database_max_retries*]
# (optional) Database reconnection retry times.
# Defaults to: 10
#
# [*database_idle_timeout*]
# (optional) Timeout before idle db connections are reaped.
# Defaults to: 3600
#
# [*database_reconnect_interval*]
# (optional) Database reconnection interval in seconds.
# Defaults to: 10
#
# [*database_retry_interval*]
# (optional) Database reconnection interval in seconds.
# Defaults to: 10
#
# [*glance_api_servers*]
# (optional) A list of the glance api servers available to ironic.
# Should be an array with [hostname|ip]:port
# Defaults to undef
#
# [*glance_num_retries*]
# (optional) Number retries when downloading an image from glance.
# Defaults to 0
#
# [*glance_api_insecure*]
# (optional) Allow to perform insecure SSL (https) requests to glance.
# Defaults to false
#
# [*sync_db*]
# Enable dbsync
# Defaults to true
#
class ironic (
$enabled = true,
$package_ensure = 'present',
$verbose = false,
$debug = false,
$auth_strategy = 'keystone',
$enabled_drivers = ['pxe_ipmitool'],
$control_exchange = 'openstack',
$rpc_backend = 'ironic.openstack.common.rpc.impl_kombu',
$rabbit_hosts = false,
$rabbit_virtual_host = '/',
$rabbit_host = 'localhost',
$rabbit_port = 5672,
$rabbit_hosts = false,
$rabbit_virtual_host = '/',
$rabbit_userid = 'guest',
$rabbit_password = false,
$rabbit_use_ssl = false,
$kombu_ssl_ca_certs = undef,
$kombu_ssl_certfile = undef,
$kombu_ssl_keyfile = undef,
$kombu_ssl_version = 'TLSv1',
$amqp_durable_queues = false,
$qpid_hostname = 'localhost',
$qpid_port = '5672',
$qpid_username = 'guest',
$qpid_password = 'guest',
$qpid_heartbeat = 60,
$qpid_protocol = 'tcp',
$qpid_tcp_nodelay = true,
$qpid_reconnect = true,
$qpid_reconnect_timeout = 0,
$qpid_reconnect_limit = 0,
$qpid_reconnect_interval_min = 0,
$qpid_reconnect_interval_max = 0,
$qpid_reconnect_interval = 0,
$use_syslog = false,
$log_facility = 'LOG_USER',
$database_connection = 'sqlite:////var/lib/ironic/ovs.sqlite',
$database_max_retries = '10',
$database_idle_timeout = '3600',
$database_reconnect_interval = '10',
$database_retry_interval = '10',
$glance_api_servers = undef,
$glance_num_retries = '0',
$glance_api_insecure = false,
$sync_db = true,
# DEPRECATED PARAMETERS
$rabbit_user = undef,
) {
include ::ironic::params
if $rabbit_user {
warning('The rabbit_user parameter is deprecated. Please use rabbit_userid instead.')
$rabbit_user_real = $rabbit_user
} else {
$rabbit_user_real = $rabbit_userid
}
file { '/etc/ironic':
ensure => directory,
require => Package['ironic-common'],
group => 'ironic',
}
file { '/etc/ironic/ironic.conf':
require => Package['ironic-common'],
group => 'ironic',
}
package { 'ironic-common':
ensure => $package_ensure,
name => $::ironic::params::common_package_name,
tag => ['openstack', 'ironic-package'],
notify => Exec['ironic-dbsync'],
}
validate_re($database_connection, '(sqlite|mysql|postgresql):\/\/(\S+:\S+@\S+\/\S+)?')
validate_array($enabled_drivers)
case $database_connection {
/mysql:\/\/\S+:\S+@\S+\/\S+/: {
$database_backend_package = false
require 'mysql::bindings'
require 'mysql::bindings::python'
}
/postgresql:\/\/\S+:\S+@\S+\/\S+/: {
$database_backend_package = 'python-psycopg2'
}
/sqlite:\/\//: {
$database_backend_package = 'python-pysqlite2'
}
default: {
fail("Invalid database connection: ${database_connection}")
}
}
if $database_backend_package and !defined(Package[$database_backend_package]) {
package { 'ironic-database-backend':
ensure => present,
name => $database_backend_package,
tag => 'openstack',
}
}
if is_array($glance_api_servers) {
ironic_config {
'glance/glance_api_servers': value => join($glance_api_servers, ',');
}
} elsif is_string($glance_api_servers) {
ironic_config {
'glance/glance_api_servers': value => $glance_api_servers;
}
}
ironic_config {
'DEFAULT/verbose': value => $verbose;
'DEFAULT/debug': value => $debug;
'DEFAULT/auth_strategy': value => $auth_strategy;
'DEFAULT/rpc_backend': value => $rpc_backend;
'DEFAULT/enabled_drivers': value => join($enabled_drivers, ',');
'database/connection': value => $database_connection, secret => true;
'database/idle_timeout': value => $database_idle_timeout;
'database/retry_interval': value => $database_retry_interval;
'database/max_retries': value => $database_max_retries;
'glance/glance_num_retries': value => $glance_num_retries;
'glance/glance_api_insecure': value => $glance_api_insecure;
}
if $sync_db {
include ::ironic::db::sync
}
if $rpc_backend == 'ironic.openstack.common.rpc.impl_kombu' {
if ! $rabbit_password {
fail('When rpc_backend is rabbitmq, you must set rabbit password')
}
ironic_config {
'oslo_messaging_rabbit/rabbit_userid': value => $rabbit_user_real;
'oslo_messaging_rabbit/rabbit_password': value => $rabbit_password, secret => true;
'oslo_messaging_rabbit/rabbit_virtual_host': value => $rabbit_virtual_host;
'oslo_messaging_rabbit/rabbit_use_ssl': value => $rabbit_use_ssl;
'DEFAULT/control_exchange': value => $control_exchange;
'DEFAULT/amqp_durable_queues': value => $amqp_durable_queues;
}
if $rabbit_hosts {
ironic_config { 'oslo_messaging_rabbit/rabbit_hosts': value => join($rabbit_hosts, ',') }
ironic_config { 'oslo_messaging_rabbit/rabbit_ha_queues': value => true }
ironic_config { 'oslo_messaging_rabbit/rabbit_host': ensure => absent }
ironic_config { 'oslo_messaging_rabbit/rabbit_port': ensure => absent }
} else {
ironic_config { 'oslo_messaging_rabbit/rabbit_host': value => $rabbit_host }
ironic_config { 'oslo_messaging_rabbit/rabbit_port': value => $rabbit_port }
ironic_config { 'oslo_messaging_rabbit/rabbit_hosts': value => "${rabbit_host}:${rabbit_port}" }
ironic_config { 'oslo_messaging_rabbit/rabbit_ha_queues': value => false }
}
if $rabbit_use_ssl {
ironic_config { 'oslo_messaging_rabbit/kombu_ssl_version': value => $kombu_ssl_version }
if $kombu_ssl_ca_certs {
ironic_config { 'oslo_messaging_rabbit/kombu_ssl_ca_certs': value => $kombu_ssl_ca_certs }
} else {
ironic_config { 'oslo_messaging_rabbit/kombu_ssl_ca_certs': ensure => absent}
}
if $kombu_ssl_certfile {
ironic_config { 'oslo_messaging_rabbit/kombu_ssl_certfile': value => $kombu_ssl_certfile }
} else {
ironic_config { 'oslo_messaging_rabbit/kombu_ssl_certfile': ensure => absent}
}
if $kombu_ssl_keyfile {
ironic_config { 'oslo_messaging_rabbit/kombu_ssl_keyfile': value => $kombu_ssl_keyfile }
} else {
ironic_config { 'oslo_messaging_rabbit/kombu_ssl_keyfile': ensure => absent}
}
} else {
ironic_config {
'oslo_messaging_rabbit/kombu_ssl_ca_certs': ensure => absent;
'oslo_messaging_rabbit/kombu_ssl_certfile': ensure => absent;
'oslo_messaging_rabbit/kombu_ssl_keyfile': ensure => absent;
'oslo_messaging_rabbit/kombu_ssl_version': ensure => absent;
}
}
}
if $rpc_backend == 'ironic.openstack.common.rpc.impl_qpid' {
ironic_config {
'DEFAULT/qpid_hostname': value => $qpid_hostname;
'DEFAULT/qpid_port': value => $qpid_port;
'DEFAULT/qpid_username': value => $qpid_username;
'DEFAULT/qpid_password': value => $qpid_password, secret => true;
'DEFAULT/qpid_heartbeat': value => $qpid_heartbeat;
'DEFAULT/qpid_protocol': value => $qpid_protocol;
'DEFAULT/qpid_tcp_nodelay': value => $qpid_tcp_nodelay;
'DEFAULT/qpid_reconnect': value => $qpid_reconnect;
'DEFAULT/qpid_reconnect_timeout': value => $qpid_reconnect_timeout;
'DEFAULT/qpid_reconnect_limit': value => $qpid_reconnect_limit;
'DEFAULT/qpid_reconnect_interval_min': value => $qpid_reconnect_interval_min;
'DEFAULT/qpid_reconnect_interval_max': value => $qpid_reconnect_interval_max;
'DEFAULT/qpid_reconnect_interval': value => $qpid_reconnect_interval;
}
}
if $use_syslog {
ironic_config {
'DEFAULT/use_syslog': value => true;
'DEFAULT/syslog_log_facility': value => $log_facility;
}
} else {
ironic_config {
'DEFAULT/use_syslog': value => false;
}
}
}

View File

@ -1,214 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# ironic::keystone::auth
#
# Configures Ironic user, service and endpoint in Keystone.
#
# === Parameters
#
# [*password*]
# (required) Password for Ironic user.
#
# [*auth_name*]
# Username for Ironic service. Defaults to 'ironic'.
#
# [*email*]
# Email for Ironic user. Defaults to 'ironic@localhost'.
#
# [*tenant*]
# Tenant for Ironic user. Defaults to 'services'.
#
# [*configure_endpoint*]
# Should Ironic endpoint be configured? Defaults to 'true'.
#
# [*configure_user*]
# (Optional) Should the service user be configured?
# Defaults to 'true'.
#
# [*configure_user_role*]
# (Optional) Should the admin role be configured for the service user?
# Defaults to 'true'.
#
# [*service_name*]
# (Optional) Name of the service.
# Defaults to the value of auth_name, but must differ from the value.
#
# [*service_type*]
# Type of service. Defaults to 'baremetal'.
#
# [*service_description*]
# (Optional) Description for keystone service.
# Defaults to 'Ironic Bare Metal Provisioning Service'.
#
# [*region*]
# Region for endpoint. Defaults to 'RegionOne'.
#
# [*public_url*]
# (optional) The endpoint's public url. (Defaults to 'http://127.0.0.1:6385')
# This url should *not* contain any trailing '/'.
#
# [*admin_url*]
# (optional) The endpoint's admin url. (Defaults to 'http://127.0.0.1:6385')
# This url should *not* contain any trailing '/'.
#
# [*internal_url*]
# (optional) The endpoint's internal url. (Defaults to 'http://127.0.0.1:6385')
# This url should *not* contain any trailing '/'.
#
# [*port*]
# (optional) DEPRECATED: Use public_url, internal_url and admin_url instead.
# Default port for endpoints. (Defaults to 6385)
# Setting this parameter overrides public_url, internal_url and admin_url parameters.
#
# [*public_protocol*]
# (optional) DEPRECATED: Use public_url instead.
# Protocol for public endpoint. (Defaults to 'http')
# Setting this parameter overrides public_url parameter.
#
# [*public_port*]
# (optional) DEPRECATED: Use public_url instead.
# Default port for endpoints. (Defaults to $port)
# Setting this parameter overrides public_url parameter.
#
# [*public_address*]
# (optional) DEPRECATED: Use public_url instead.
# Public address for endpoint. (Defaults to '127.0.0.1')
# Setting this parameter overrides public_url parameter.
#
# [*internal_address*]
# (optional) DEPRECATED: Use internal_url instead.
# Internal address for endpoint. (Defaults to '127.0.0.1')
# Setting this parameter overrides internal_url parameter.
#
# [*admin_address*]
# (optional) DEPRECATED: Use admin_url instead.
# Admin address for endpoint. (Defaults to '127.0.0.1')
# Setting this parameter overrides admin_url parameter.
#
# === Deprecation notes
#
# If any value is provided for public_protocol, public_address or port parameters,
# public_url will be completely ignored. The same applies for internal and admin parameters.
#
# === Examples
#
# class { 'ironic::keystone::auth':
# public_url => 'https://10.0.0.10:6385',
# internal_url => 'https://10.0.0.11:6385',
# admin_url => 'https://10.0.0.11:6385',
# }
#
class ironic::keystone::auth (
$password,
$auth_name = 'ironic',
$email = 'ironic@localhost',
$tenant = 'services',
$configure_endpoint = true,
$configure_user = true,
$configure_user_role = true,
$service_name = undef,
$service_type = 'baremetal',
$service_description = 'Ironic Bare Metal Provisioning Service',
$public_protocol = 'http',
$region = 'RegionOne',
$public_url = 'http://127.0.0.1:6385',
$admin_url = 'http://127.0.0.1:6385',
$internal_url = 'http://127.0.0.1:6385',
# DEPRECATED PARAMETERS
$port = undef,
$public_protocol = undef,
$public_address = undef,
$public_port = undef,
$internal_address = undef,
$admin_address = undef,
) {
if $port {
warning('The port parameter is deprecated, use public_url, internal_url and admin_url instead.')
}
if $public_port {
warning('The public_port parameter is deprecated, use public_url instead.')
}
if $public_protocol {
warning('The public_protocol parameter is deprecated, use public_url instead.')
}
if $public_address {
warning('The public_address parameter is deprecated, use public_url instead.')
}
if $internal_address {
warning('The internal_address parameter is deprecated, use internal_url instead.')
}
if $admin_address {
warning('The admin_address parameter is deprecated, use admin_url instead.')
}
if ($public_protocol or $public_address or $port or $public_port) {
$public_url_real = sprintf('%s://%s:%s',
pick($public_protocol, 'http'),
pick($public_address, '127.0.0.1'),
pick($public_port, $port, '6385'))
} else {
$public_url_real = $public_url
}
if ($admin_address or $port) {
$admin_url_real = sprintf('http://%s:%s',
pick($admin_address, '127.0.0.1'),
pick($port, '6385'))
} else {
$admin_url_real = $admin_url
}
if ($internal_address or $port) {
$internal_url_real = sprintf('http://%s:%s',
pick($internal_address, '127.0.0.1'),
pick($port, '6385'))
} else {
$internal_url_real = $internal_url
}
$real_service_name = pick($service_name, $auth_name)
if $configure_user_role {
Keystone_user_role["${auth_name}@${tenant}"] ~> Service <| name == 'ironic-server' |>
}
Keystone_endpoint["${region}/${real_service_name}"] ~> Service <| name == 'ironic-server' |>
keystone::resource::service_identity { $auth_name:
configure_user => $configure_user,
configure_user_role => $configure_user_role,
configure_endpoint => $configure_endpoint,
service_name => $real_service_name,
service_type => $service_type,
service_description => $service_description,
region => $region,
password => $password,
email => $email,
tenant => $tenant,
public_url => $public_url_real,
internal_url => $internal_url_real,
admin_url => $admin_url_real,
}
}

View File

@ -1,48 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# ironic::params
#
class ironic::params {
$dbsync_command =
'ironic-dbsync --config-file /etc/ironic/ironic.conf'
case $::osfamily {
'RedHat': {
$common_package_name = 'openstack-ironic-common'
$api_package = 'openstack-ironic-api'
$api_service = 'openstack-ironic-api'
$conductor_package = 'openstack-ironic-conductor'
$conductor_service = 'openstack-ironic-conductor'
$client_package = 'python-ironicclient'
}
'Debian': {
$common_package_name = 'ironic-common'
$api_service = 'ironic-api'
$api_package = 'ironic-api'
$conductor_service = 'ironic-conductor'
$conductor_package = 'ironic-conductor'
$client_package = 'python-ironicclient'
}
default: {
fail("Unsupported osfamily ${::osfamily}")
}
}
}

View File

@ -1,29 +0,0 @@
# == Class: ironic::policy
#
# Configure the ironic policies
#
# === Parameters
#
# [*policies*]
# (optional) Set of policies to configure for ironic
# Example : { 'ironic-context_is_admin' => {'context_is_admin' => 'true'}, 'ironic-default' => {'default' => 'rule:admin_or_owner'} }
# Defaults to empty hash.
#
# [*policy_path*]
# (optional) Path to the ironic policy.json file
# Defaults to /etc/ironic/policy.json
#
class ironic::policy (
$policies = {},
$policy_path = '/etc/ironic/policy.json',
) {
validate_hash($policies)
Openstacklib::Policy::Base {
file_path => $policy_path,
}
create_resources('openstacklib::policy::base', $policies)
}

View File

@ -1,40 +0,0 @@
{
"name": "openstack-ironic",
"version": "6.0.0",
"author": "eNovance and OpenStack Contributors",
"summary": "Puppet module for OpenStack Ironic",
"license": "Apache-2.0",
"source": "git://github.com/openstack/puppet-ironic.git",
"project_page": "https://launchpad.net/puppet-ironic",
"issues_url": "https://bugs.launchpad.net/puppet-ironic",
"requirements": [
{ "name": "pe","version_requirement": "3.x" },
{ "name": "puppet","version_requirement": "3.x" }
],
"operatingsystem_support": [
{
"operatingsystem": "Debian",
"operatingsystemrelease": ["7"]
},
{
"operatingsystem": "Fedora",
"operatingsystemrelease": ["20"]
},
{
"operatingsystem": "RedHat",
"operatingsystemrelease": ["6.5","7"]
},
{
"operatingsystem": "Ubuntu",
"operatingsystemrelease": ["12.04","14.04"]
}
],
"description": "Installs and configures OpenStack Ironic (Bare metal).",
"dependencies": [
{ "name": "puppetlabs/inifile", "version_requirement": ">=1.0.0 <2.0.0" },
{ "name": "openstack/keystone", "version_requirement": ">=6.0.0 <7.0.0" },
{ "name": "puppetlabs/stdlib", "version_requirement": ">=4.0.0 <5.0.0" },
{ "name": "openstack/openstacklib", "version_requirement": ">=6.0.0 <7.0.0" },
{ "name": "puppetlabs/vcsrepo", "version_requirement": ">=1.3.0 <2.0.0"}
]
}

View File

@ -1,130 +0,0 @@
require 'spec_helper_acceptance'
describe 'basic ironic' do
context 'default parameters' do
it 'should work with no errors' do
pp= <<-EOS
Exec { logoutput => 'on_failure' }
# Common resources
case $::osfamily {
'Debian': {
include ::apt
class { '::openstack_extras::repo::debian::ubuntu':
release => 'kilo',
package_require => true,
}
$package_provider = 'apt'
}
'RedHat': {
class { '::openstack_extras::repo::redhat::redhat':
# Kilo is not GA yet, so let's use the testing repo
manage_rdo => false,
repo_hash => {
'rdo-kilo-testing' => {
'baseurl' => 'https://repos.fedorapeople.org/repos/openstack/openstack-kilo/testing/el7/',
# packages are not GA so not signed
'gpgcheck' => '0',
'priority' => 97,
},
},
}
$package_provider = 'yum'
}
default: {
fail("Unsupported osfamily (${::osfamily})")
}
}
class { '::mysql::server': }
class { '::rabbitmq':
delete_guest_user => true,
package_provider => $package_provider,
}
rabbitmq_vhost { '/':
provider => 'rabbitmqctl',
require => Class['rabbitmq'],
}
rabbitmq_user { 'ironic':
admin => true,
password => 'an_even_bigger_secret',
provider => 'rabbitmqctl',
require => Class['rabbitmq'],
}
rabbitmq_user_permissions { 'ironic@/':
configure_permission => '.*',
write_permission => '.*',
read_permission => '.*',
provider => 'rabbitmqctl',
require => Class['rabbitmq'],
}
# Keystone resources, needed by Ironic to run
class { '::keystone::db::mysql':
password => 'keystone',
}
class { '::keystone':
verbose => true,
debug => true,
database_connection => 'mysql://keystone:keystone@127.0.0.1/keystone',
admin_token => 'admin_token',
enabled => true,
}
class { '::keystone::roles::admin':
email => 'test@example.tld',
password => 'a_big_secret',
}
class { '::keystone::endpoint':
public_url => "https://${::fqdn}:5000/",
admin_url => "https://${::fqdn}:35357/",
}
case $::osfamily {
'Debian': {
# Ironic resources
class { '::ironic':
rabbit_userid => 'ironic',
rabbit_password => 'an_even_bigger_secret',
rabbit_host => '127.0.0.1',
database_connection => 'mysql://ironic:a_big_secret@127.0.0.1/ironic?charset=utf8',
}
class { '::ironic::db::mysql':
password => 'a_big_secret',
}
class { '::ironic::keystone::auth':
password => 'a_big_secret',
}
class { '::ironic::client': }
class { '::ironic::conductor': }
class { '::ironic::api':
admin_password => 'a_big_secret',
}
class { '::ironic::drivers::ipmi': }
}
'RedHat': {
warning("Ironic packaging is not ready on ${::osfamily}.")
}
}
EOS
# Run it twice and test for idempotency
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => true)
end
if os[:family] == 'Debian'
describe port(6385) do
it { is_expected.to be_listening.with('tcp') }
end
end
end
end

View File

@ -1,9 +0,0 @@
HOSTS:
ubuntu-14.04-amd64:
roles:
- master
platform: ubuntu-14.04-amd64
hypervisor : none
ip: 127.0.0.1
CONFIG:
type: foss

View File

@ -1,10 +0,0 @@
HOSTS:
centos-70-x64:
roles:
- master
platform: el-7-x86_64
hypervisor : none
ip: 127.0.0.1
CONFIG:
type: foss
set_env: false

View File

@ -1,10 +0,0 @@
HOSTS:
ubuntu-14.04-amd64:
roles:
- master
platform: ubuntu-14.04-amd64
hypervisor : none
ip: 127.0.0.1
CONFIG:
type: foss
set_env: false

View File

@ -1,120 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Unit tests for ironic::api class
#
require 'spec_helper'
describe 'ironic::api' do
let :default_params do
{ :package_ensure => 'present',
:enabled => true,
:port => '6385',
:max_limit => '1000',
:host_ip => '0.0.0.0',
:admin_user => 'ironic',
}
end
let :params do
{ :admin_password => 'thepassword' }
end
shared_examples_for 'ironic api' do
let :p do
default_params.merge(params)
end
it { is_expected.to contain_class('ironic::params') }
it { is_expected.to contain_class('ironic::policy') }
it 'installs ironic api package' do
if platform_params.has_key?(:api_package)
is_expected.to contain_package('ironic-api').with(
:name => platform_params[:api_package],
:ensure => p[:package_ensure],
:tag => ['openstack', 'ironic-package'],
)
is_expected.to contain_package('ironic-api').with_before(/Service\[ironic-api\]/)
end
end
it 'ensure ironic api service is running' do
is_expected.to contain_service('ironic-api').with(
'hasstatus' => true,
'tag' => 'ironic-service',
)
end
it 'configures ironic.conf' do
is_expected.to contain_ironic_config('api/port').with_value(p[:port])
is_expected.to contain_ironic_config('api/host_ip').with_value(p[:host_ip])
is_expected.to contain_ironic_config('api/max_limit').with_value(p[:max_limit])
is_expected.to contain_ironic_config('keystone_authtoken/admin_password').with_value(p[:admin_password])
is_expected.to contain_ironic_config('keystone_authtoken/admin_user').with_value(p[:admin_user])
is_expected.to contain_ironic_config('keystone_authtoken/auth_uri').with_value('http://127.0.0.1:5000/')
is_expected.to contain_ironic_config('neutron/url').with_value('http://127.0.0.1:9696/')
end
context 'when overriding parameters' do
before :each do
params.merge!(
:port => '3430',
:host_ip => '127.0.0.1',
:max_limit => '10',
:auth_protocol => 'https',
:auth_host => '1.2.3.4'
)
end
it 'should replace default parameter with new value' do
is_expected.to contain_ironic_config('api/port').with_value(p[:port])
is_expected.to contain_ironic_config('api/host_ip').with_value(p[:host_ip])
is_expected.to contain_ironic_config('api/max_limit').with_value(p[:max_limit])
is_expected.to contain_ironic_config('keystone_authtoken/auth_uri').with_value('https://1.2.3.4:5000/')
end
end
end
context 'on Debian platforms' do
let :facts do
{ :osfamily => 'Debian' }
end
let :platform_params do
{ :api_package => 'ironic-api',
:api_service => 'ironic-api' }
end
it_configures 'ironic api'
end
context 'on RedHat platforms' do
let :facts do
{ :osfamily => 'RedHat' }
end
let :platform_params do
{ :api_service => 'ironic-api' }
end
it_configures 'ironic api'
end
end

View File

@ -1,84 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Unit tests for ironic::bifrost class
#
require 'spec_helper'
describe 'ironic::bifrost' do
let :default_params do
{ :git_source_repo => 'https://git.openstack.org/openstack/bifrost',
:revision => master,
:git_dest_repo_folder => '/opt/stack/bifrost',
:ironic_url => '"http://localhost:6385/"',
:network_interface => '"virbr0"',
:testing => false,
:testing_user => 'ubuntu',
:http_boot_folder => '/httpboot',
:nginx_port => 8080,
:ssh_public_key_path => '"{{ ansible_env.HOME }}/.ssh/id_rsa.pub"',
:deploy_kernel => '"{{http_boot_folder}}/coreos_production_pxe.vmlinuz"',
:deploy_ramdisk => '"{{http_boot_folder}}/coreos_production_pxe_image-oem.cpio.gz"',
:deploy_kernel_url => '"http://{{ hostvars[inventory_hostname][\'ansible_\' + network_interface][\'ipv4\'][\'address\'] }}:{{nginx_port}}/coreos_production_pxe.vmlinuz"',
:deploy_ramdisk_url => '"http://{{ hostvars[inventory_hostname][\'ansible_\' + network_interface][\'ipv4\'][\'address\'] }}:{{nginx_port}}/coreos_production_pxe_image-oem.cpio.gz"',
:deploy_image_filename => '"deployment_image.qcow2"',
:deploy_image => '"{{http_boot_folder}}/{{deploy_image_filename}}"',
:create_image_via_dib => true,
:transform_boot_image => false,
:node_default_network_interface => 'eth0',
:ipv4_subnet_mask => '255.255.255.0',
:ipv4_gateway => '192.168.1.1',
:ipv4_nameserver => '8.8.8.8',
:network_mtu => '1500',
:dhcp_pool_start => '192.168.1.200',
:dhcp_pool_end => '192.168.1.250',
:ipmi_bridging => 'no',
}
end
let :params do
{ :mysql_password => 'changeme',
:ironic_db_password => 'changeme',
:baremetal_json_hosts => 'test',
}
end
it 'should clone with vcsrepo bifrost repo with master branch' do
should contain_vcsrepo('/opt/stack/bifrost').with(
'ensure' => 'present',
'provider' => 'git',
'revision' => 'master',
'source' => 'https://git.openstack.org/openstack/bifrost',
)
end
it 'should contain file group_vars/all' do
should contain_file('/opt/stack/bifrost/playbooks/inventory/group_vars/all').with(
'ensure' => 'present',
'require' => 'Vcsrepo[/opt/stack/bifrost]',
'content' => /ironic_url/,
)
end
it 'should contain file baremetal.json' do
should contain_file('/opt/stack/bifrost/baremetal.json').with(
'ensure' => 'present',
'require' => 'Vcsrepo[/opt/stack/bifrost]',
'content' => /test/,
)
end
end

View File

@ -1,40 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Unit tests for ironic::client
#
require 'spec_helper'
describe 'ironic::client' do
context 'on Debian platforms' do
let :facts do
{ :osfamily => 'Debian' }
end
it { is_expected.to contain_class('ironic::client') }
end
context 'on RedHat platforms' do
let :facts do
{ :osfamily => 'RedHat' }
end
it { is_expected.to contain_class('ironic::client') }
end
end

View File

@ -1,106 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Unit tests for ironic::conductor class
#
require 'spec_helper'
describe 'ironic::conductor' do
let :default_params do
{ :package_ensure => 'present',
:enabled => true,
:max_time_interval => '120',
:force_power_state_during_sync => true }
end
let :params do
{}
end
shared_examples_for 'ironic conductor' do
let :p do
default_params.merge(params)
end
it { is_expected.to contain_class('ironic::params') }
it 'installs ironic conductor package' do
if platform_params.has_key?(:conductor_package)
is_expected.to contain_package('ironic-conductor').with(
:name => platform_params[:conductor_package],
:ensure => p[:package_ensure],
:tag => ['openstack', 'ironic-package'],
)
is_expected.to contain_package('ironic-conductor').with_before(/Service\[ironic-conductor\]/)
end
end
it 'ensure ironic conductor service is running' do
is_expected.to contain_service('ironic-conductor').with(
'hasstatus' => true,
'tag' => 'ironic-service',
)
end
it 'configures ironic.conf' do
is_expected.to contain_ironic_config('conductor/max_time_interval').with_value(p[:max_time_interval])
is_expected.to contain_ironic_config('conductor/force_power_state_during_sync').with_value(p[:force_power_state_during_sync])
end
context 'when overriding parameters' do
before :each do
params.merge!(
:max_time_interval => '50',
:force_power_state_during_sync => false
)
end
it 'should replace default parameter with new value' do
is_expected.to contain_ironic_config('conductor/max_time_interval').with_value(p[:max_time_interval])
is_expected.to contain_ironic_config('conductor/force_power_state_during_sync').with_value(p[:force_power_state_during_sync])
end
end
end
context 'on Debian platforms' do
let :facts do
{ :osfamily => 'Debian' }
end
let :platform_params do
{ :conductor_package => 'ironic-conductor',
:conductor_service => 'ironic-conductor' }
end
it_configures 'ironic conductor'
end
context 'on RedHat platforms' do
let :facts do
{ :osfamily => 'RedHat' }
end
let :platform_params do
{ :conductor_service => 'ironic-conductor' }
end
it_configures 'ironic conductor'
end
end

View File

@ -1,20 +0,0 @@
require 'spec_helper'
describe 'ironic::config' do
let :params do
{ :ironic_config => {
'DEFAULT/foo' => { 'value' => 'fooValue' },
'DEFAULT/bar' => { 'value' => 'barValue' },
'DEFAULT/baz' => { 'ensure' => 'absent' }
}
}
end
it 'configures arbitrary ironic configurations' do
is_expected.to contain_ironic_config('DEFAULT/foo').with_value('fooValue')
is_expected.to contain_ironic_config('DEFAULT/bar').with_value('barValue')
is_expected.to contain_ironic_config('DEFAULT/baz').with_ensure('absent')
end
end

View File

@ -1,89 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Unit tests for ironic::db::mysql
#
require 'spec_helper'
describe 'ironic::db::mysql' do
let :pre_condition do
'include mysql::server'
end
let :params do
{ :password => 'passw0rd' }
end
let :facts do
{ :osfamily => 'Debian' }
end
context 'on Debian platforms' do
let :facts do
{ :osfamily => 'Debian' }
end
it { is_expected.to contain_openstacklib__db__mysql('ironic').with(
:user => 'ironic',
:password_hash => '*74B1C21ACE0C2D6B0678A5E503D2A60E8F9651A3',
:charset => 'utf8',
:collate => 'utf8_general_ci',
)}
end
context 'on RedHat platforms' do
let :facts do
{ :osfamily => 'RedHat' }
end
it { is_expected.to contain_openstacklib__db__mysql('ironic').with(
:user => 'ironic',
:password_hash => '*74B1C21ACE0C2D6B0678A5E503D2A60E8F9651A3',
:charset => 'utf8',
:collate => 'utf8_general_ci',
)}
end
describe "overriding allowed_hosts param to array" do
let :params do
{
:allowed_hosts => ['127.0.0.1','%']
}
end
end
describe "overriding allowed_hosts param to string" do
let :params do
{
:allowed_hosts => '192.168.1.1'
}
end
end
describe "overriding allowed_hosts param equals to host param " do
let :params do
{
:allowed_hosts => '127.0.0.1'
}
end
end
end

View File

@ -1,58 +0,0 @@
require 'spec_helper'
describe 'ironic::db::postgresql' do
let :req_params do
{ :password => 'pw' }
end
let :pre_condition do
'include postgresql::server'
end
context 'on a RedHat osfamily' do
let :facts do
{
:osfamily => 'RedHat',
:operatingsystemrelease => '7.0',
:concat_basedir => '/var/lib/puppet/concat'
}
end
context 'with only required parameters' do
let :params do
req_params
end
it { is_expected.to contain_postgresql__server__db('ironic').with(
:user => 'ironic',
:password => 'md554bdb85e136b50c40104fd9f73e1294d'
)}
end
end
context 'on a Debian osfamily' do
let :facts do
{
:operatingsystemrelease => '7.8',
:operatingsystem => 'Debian',
:osfamily => 'Debian',
:concat_basedir => '/var/lib/puppet/concat'
}
end
context 'with only required parameters' do
let :params do
req_params
end
it { is_expected.to contain_postgresql__server__db('ironic').with(
:user => 'ironic',
:password => 'md554bdb85e136b50c40104fd9f73e1294d'
)}
end
end
end

View File

@ -1,44 +0,0 @@
require 'spec_helper'
describe 'ironic::db::sync' do
shared_examples_for 'ironic-dbsync' do
it 'runs ironic-manage db_sync' do
is_expected.to contain_exec('ironic-dbsync').with(
:command => 'ironic-dbsync --config-file /etc/ironic/ironic.conf',
:path => '/usr/bin',
:user => 'root',
:refreshonly => 'true',
:logoutput => 'on_failure'
)
end
end
context 'on a RedHat osfamily' do
let :facts do
{
:osfamily => 'RedHat',
:operatingsystemrelease => '7.0',
:concat_basedir => '/var/lib/puppet/concat'
}
end
it_configures 'ironic-dbsync'
end
context 'on a Debian osfamily' do
let :facts do
{
:operatingsystemrelease => '7.8',
:operatingsystem => 'Debian',
:osfamily => 'Debian',
:concat_basedir => '/var/lib/puppet/concat'
}
end
it_configures 'ironic-dbsync'
end
end

View File

@ -1,69 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Unit tests for ironic::drivers::ipmi class
#
require 'spec_helper'
describe 'ironic::drivers::ipmi' do
let :default_params do
{ :retry_timeout => '10' }
end
let :params do
{}
end
shared_examples_for 'ironic ipmi driver' do
let :p do
default_params.merge(params)
end
it 'configures ironic.conf' do
is_expected.to contain_ironic_config('ipmi/retry_timeout').with_value(p[:retry_timeout])
end
context 'when overriding parameters' do
before do
params.merge!(:retry_timeout => '50')
end
it 'should replace default parameter with new value' do
is_expected.to contain_ironic_config('ipmi/retry_timeout').with_value(p[:retry_timeout])
end
end
end
context 'on Debian platforms' do
let :facts do
{ :osfamily => 'Debian' }
end
it_configures 'ironic ipmi driver'
end
context 'on RedHat platforms' do
let :facts do
{ :osfamily => 'RedHat' }
end
it_configures 'ironic ipmi driver'
end
end

View File

@ -1,104 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Unit tests for ironic::drivers::pxe class
#
require 'spec_helper'
describe 'ironic::drivers::pxe' do
let :default_params do
{ :pxe_append_params => 'nofb nomodeset vga=normal',
:pxe_config_template => '$pybasedir/drivers/modules/pxe_config.template',
:pxe_deploy_timeout => '0',
:tftp_server => '$my_ip',
:tftp_root => '/tftpboot',
:images_path => '/var/lib/ironic/images/',
:tftp_master_path => '/tftpboot/master_images',
:instance_master_path => '/var/lib/ironic/master_images' }
end
let :params do
{}
end
shared_examples_for 'ironic pxe driver' do
let :p do
default_params.merge(params)
end
it 'configures ironic.conf' do
is_expected.to contain_ironic_config('pxe/pxe_append_params').with_value(p[:pxe_append_params])
is_expected.to contain_ironic_config('pxe/pxe_config_template').with_value(p[:pxe_config_template])
is_expected.to contain_ironic_config('pxe/pxe_deploy_timeout').with_value(p[:pxe_deploy_timeout])
is_expected.to contain_ironic_config('pxe/tftp_server').with_value(p[:tftp_server])
is_expected.to contain_ironic_config('pxe/tftp_root').with_value(p[:tftp_root])
is_expected.to contain_ironic_config('pxe/images_path').with_value(p[:images_path])
is_expected.to contain_ironic_config('pxe/tftp_master_path').with_value(p[:tftp_master_path])
is_expected.to contain_ironic_config('pxe/instance_master_path').with_value(p[:instance_master_path])
end
context 'when overriding parameters' do
before do
params.merge!(
:deploy_kernel => 'foo',
:deploy_ramdisk => 'bar',
:pxe_append_params => 'foo',
:pxe_config_template => 'bar',
:pxe_deploy_timeout => '40',
:tftp_server => '192.168.0.1',
:tftp_root => '/mnt/ftp',
:images_path => '/mnt/images',
:tftp_master_path => '/mnt/master_images',
:instance_master_path => '/mnt/ironic/master_images'
)
end
it 'should replace default parameter with new value' do
is_expected.to contain_ironic_config('pxe/deploy_kernel').with_value(p[:deploy_kernel])
is_expected.to contain_ironic_config('pxe/deploy_ramdisk').with_value(p[:deploy_ramdisk])
is_expected.to contain_ironic_config('pxe/pxe_append_params').with_value(p[:pxe_append_params])
is_expected.to contain_ironic_config('pxe/pxe_config_template').with_value(p[:pxe_config_template])
is_expected.to contain_ironic_config('pxe/pxe_deploy_timeout').with_value(p[:pxe_deploy_timeout])
is_expected.to contain_ironic_config('pxe/tftp_server').with_value(p[:tftp_server])
is_expected.to contain_ironic_config('pxe/tftp_root').with_value(p[:tftp_root])
is_expected.to contain_ironic_config('pxe/images_path').with_value(p[:images_path])
is_expected.to contain_ironic_config('pxe/tftp_master_path').with_value(p[:tftp_master_path])
is_expected.to contain_ironic_config('pxe/instance_master_path').with_value(p[:instance_master_path])
end
end
end
context 'on Debian platforms' do
let :facts do
{ :osfamily => 'Debian' }
end
it_configures 'ironic pxe driver'
end
context 'on RedHat platforms' do
let :facts do
{ :osfamily => 'RedHat' }
end
it_configures 'ironic pxe driver'
end
end

View File

@ -1,315 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Unit tests for ironic
#
require 'spec_helper'
describe 'ironic' do
let :params do
{ :package_ensure => 'present',
:verbose => false,
:debug => false,
:enabled_drivers => ['pxe_ipmitool'],
:rabbit_host => '127.0.0.1',
:rabbit_port => 5672,
:rabbit_hosts => false,
:rabbit_userid => 'guest',
:rabbit_password => 'guest',
:rabbit_virtual_host => '/',
:database_connection => 'sqlite:////var/lib/ironic/ironic.sqlite',
:database_max_retries => 10,
:database_idle_timeout => 3600,
:database_reconnect_interval => 10,
:database_retry_interval => 10,
:glance_num_retries => 0,
:glance_api_insecure => false
}
end
shared_examples_for 'ironic' do
context 'and if rabbit_host parameter is provided' do
it_configures 'a ironic base installation'
it_configures 'with SSL disabled'
it_configures 'with SSL enabled without kombu'
it_configures 'with SSL enabled with kombu'
end
context 'and if rabbit_hosts parameter is provided' do
before do
params.delete(:rabbit_host)
params.delete(:rabbit_port)
end
context 'with one server' do
before { params.merge!( :rabbit_hosts => ['127.0.0.1:5672'] ) }
it_configures 'a ironic base installation'
it_configures 'rabbit HA with a single virtual host'
end
context 'with multiple servers' do
before { params.merge!( :rabbit_hosts => ['rabbit1:5672', 'rabbit2:5672'] ) }
it_configures 'a ironic base installation'
it_configures 'rabbit HA with multiple hosts'
end
end
context 'with mysql database backend' do
before do
params.merge!(:database_connection => 'mysql://ironic:ironic@localhost/ironic')
end
end
context 'with sqlite database backend' do
before do
params.merge!(:database_connection => 'sqlite:////var/lib/ironic/ironic.sqlite')
end
it { is_expected.to contain_package('ironic-database-backend').with_name('python-pysqlite2')}
end
context 'with postgresql database backend' do
before do
params.merge!(:database_connection => 'postgresql://ironic:ironic@localhost/ironic')
end
it { is_expected.to contain_package('ironic-database-backend').with_name('python-psycopg2')}
end
it_configures 'with syslog disabled'
it_configures 'with syslog enabled'
it_configures 'with syslog enabled and custom settings'
end
shared_examples_for 'a ironic base installation' do
it { is_expected.to contain_class('ironic::params') }
it 'configures ironic configuration folder' do
is_expected.to contain_file('/etc/ironic/').with(
:ensure => 'directory',
:group => 'ironic',
:require => 'Package[ironic-common]'
)
end
it 'configures ironic configuration file' do
is_expected.to contain_file('/etc/ironic/ironic.conf').with(
:group => 'ironic',
:require => 'Package[ironic-common]'
)
end
it 'installs ironic package' do
is_expected.to contain_package('ironic-common').with(
:ensure => 'present',
:name => platform_params[:common_package_name],
:tag => ['openstack', 'ironic-package'],
)
end
it 'configures enabled_drivers' do
is_expected.to contain_ironic_config('DEFAULT/enabled_drivers').with_value( params[:enabled_drivers] )
end
it 'configures credentials for rabbit' do
is_expected.to contain_ironic_config('oslo_messaging_rabbit/rabbit_userid').with_value( params[:rabbit_userid] )
is_expected.to contain_ironic_config('oslo_messaging_rabbit/rabbit_password').with_value( params[:rabbit_password] )
is_expected.to contain_ironic_config('oslo_messaging_rabbit/rabbit_virtual_host').with_value( params[:rabbit_virtual_host] )
is_expected.to contain_ironic_config('oslo_messaging_rabbit/rabbit_password').with_secret( true )
end
it 'should perform default database configuration' do
is_expected.to contain_ironic_config('database/connection').with_value(params[:database_connection])
is_expected.to contain_ironic_config('database/max_retries').with_value(params[:database_max_retries])
is_expected.to contain_ironic_config('database/idle_timeout').with_value(params[:database_idle_timeout])
is_expected.to contain_ironic_config('database/retry_interval').with_value(params[:database_retry_interval])
end
it 'configures glance connection' do
is_expected.to contain_ironic_config('glance/glance_num_retries').with_value(params[:glance_num_retries])
is_expected.to contain_ironic_config('glance/glance_api_insecure').with_value(params[:glance_api_insecure])
end
it 'configures ironic.conf' do
is_expected.to contain_ironic_config('DEFAULT/verbose').with_value( params[:verbose] )
is_expected.to contain_ironic_config('DEFAULT/auth_strategy').with_value('keystone')
is_expected.to contain_ironic_config('DEFAULT/control_exchange').with_value('openstack')
end
end
shared_examples_for 'rabbit HA with a single virtual host' do
it 'in ironic.conf' do
is_expected.to contain_ironic_config('oslo_messaging_rabbit/rabbit_host').with_ensure('absent')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/rabbit_port').with_ensure('absent')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/rabbit_hosts').with_value( params[:rabbit_hosts] )
is_expected.to contain_ironic_config('oslo_messaging_rabbit/rabbit_ha_queues').with_value(true)
end
end
shared_examples_for 'rabbit HA with multiple hosts' do
it 'in ironic.conf' do
is_expected.to contain_ironic_config('oslo_messaging_rabbit/rabbit_host').with_ensure('absent')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/rabbit_port').with_ensure('absent')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/rabbit_hosts').with_value( params[:rabbit_hosts].join(',') )
is_expected.to contain_ironic_config('oslo_messaging_rabbit/rabbit_ha_queues').with_value(true)
end
end
shared_examples_for 'with SSL enabled with kombu' do
before do
params.merge!(
:rabbit_use_ssl => true,
:kombu_ssl_ca_certs => '/path/to/ssl/ca/certs',
:kombu_ssl_certfile => '/path/to/ssl/cert/file',
:kombu_ssl_keyfile => '/path/to/ssl/keyfile',
:kombu_ssl_version => 'TLSv1'
)
end
it do
is_expected.to contain_ironic_config('oslo_messaging_rabbit/rabbit_use_ssl').with_value('true')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/kombu_ssl_ca_certs').with_value('/path/to/ssl/ca/certs')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/kombu_ssl_certfile').with_value('/path/to/ssl/cert/file')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/kombu_ssl_keyfile').with_value('/path/to/ssl/keyfile')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/kombu_ssl_version').with_value('TLSv1')
end
end
shared_examples_for 'with SSL enabled without kombu' do
before do
params.merge!(
:rabbit_use_ssl => true,
)
end
it do
is_expected.to contain_ironic_config('oslo_messaging_rabbit/rabbit_use_ssl').with_value('true')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/kombu_ssl_ca_certs').with_ensure('absent')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/kombu_ssl_certfile').with_ensure('absent')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/kombu_ssl_keyfile').with_ensure('absent')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/kombu_ssl_version').with_value('TLSv1')
end
end
shared_examples_for 'with SSL disabled' do
before do
params.merge!(
:rabbit_use_ssl => false,
:kombu_ssl_ca_certs => 'undef',
:kombu_ssl_certfile => 'undef',
:kombu_ssl_keyfile => 'undef',
:kombu_ssl_version => 'TLSv1'
)
end
it do
is_expected.to contain_ironic_config('oslo_messaging_rabbit/rabbit_use_ssl').with_value('false')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/kombu_ssl_ca_certs').with_ensure('absent')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/kombu_ssl_certfile').with_ensure('absent')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/kombu_ssl_keyfile').with_ensure('absent')
is_expected.to contain_ironic_config('oslo_messaging_rabbit/kombu_ssl_version').with_ensure('absent')
end
end
shared_examples_for 'with amqp_durable_queues disabled' do
it { is_expected.to contain_ironic_config('DEFAULT/amqp_durable_queues').with_value(false) }
end
shared_examples_for 'with amqp_durable_queues enabled' do
before do
params.merge( :amqp_durable_queues => true )
end
it { is_expected.to contain_ironic_config('DEFAULT/amqp_durable_queues').with_value(true) }
end
shared_examples_for 'with syslog disabled' do
it { is_expected.to contain_ironic_config('DEFAULT/use_syslog').with_value(false) }
end
shared_examples_for 'with syslog enabled' do
before do
params.merge!( :use_syslog => true )
end
it do
is_expected.to contain_ironic_config('DEFAULT/use_syslog').with_value(true)
is_expected.to contain_ironic_config('DEFAULT/syslog_log_facility').with_value('LOG_USER')
end
end
shared_examples_for 'with syslog enabled and custom settings' do
before do
params.merge!(
:use_syslog => true,
:log_facility => 'LOG_LOCAL0'
)
end
it do
is_expected.to contain_ironic_config('DEFAULT/use_syslog').with_value(true)
is_expected.to contain_ironic_config('DEFAULT/syslog_log_facility').with_value('LOG_LOCAL0')
end
end
shared_examples_for 'with one glance server' do
before do
params.merge!(:glance_api_servers => '10.0.0.1:9292')
end
it 'should configure one glance server' do
is_expected.to contain_ironic_config('glance/glance_api_servers').with_value(p[:glance_api_servers])
end
end
shared_examples_for 'with two glance servers' do
before do
params.merge!(:glance_api_servers => ['10.0.0.1:9292','10.0.0.2:9292'])
end
it 'should configure one glance server' do
is_expected.to contain_ironic_config('glance/glance_api_servers').with_value(p[:glance_api_servers].join(','))
end
end
context 'on Debian platforms' do
let :facts do
{ :osfamily => 'Debian' }
end
let :platform_params do
{ :common_package_name => 'ironic-common' }
end
it_configures 'ironic'
end
context 'on RedHat platforms' do
let :facts do
{ :osfamily => 'RedHat' }
end
let :platform_params do
{ :common_package_name => 'openstack-ironic-common' }
end
it_configures 'ironic'
end
end

View File

@ -1,177 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Unit tests for ironic::keystone::auth
#
require 'spec_helper'
describe 'ironic::keystone::auth' do
let :facts do
{ :osfamily => 'Debian' }
end
describe 'with default class parameters' do
let :params do
{ :password => 'ironic_password',
:tenant => 'foobar' }
end
it { is_expected.to contain_keystone_user('ironic').with(
:ensure => 'present',
:password => 'ironic_password',
:tenant => 'foobar'
) }
it { is_expected.to contain_keystone_user_role('ironic@foobar').with(
:ensure => 'present',
:roles => ['admin']
)}
it { is_expected.to contain_keystone_service('ironic').with(
:ensure => 'present',
:type => 'baremetal',
:description => 'Ironic Bare Metal Provisioning Service'
) }
it { is_expected.to contain_keystone_endpoint('RegionOne/ironic').with(
:ensure => 'present',
:public_url => "http://127.0.0.1:6385",
:admin_url => "http://127.0.0.1:6385",
:internal_url => "http://127.0.0.1:6385"
) }
end
describe 'when configuring ironic-server' do
let :pre_condition do
"class { 'ironic::server': auth_password => 'test' }"
end
let :params do
{ :password => 'ironic_password',
:tenant => 'foobar' }
end
#FIXME it { should contain_keystone_endpoint('RegionOne/ironic').with_notify('Service[ironic-server]') }
end
describe 'with endpoint parameters' do
let :params do
{ :password => 'ironic_password',
:public_url => 'https://10.0.0.10:6385',
:admin_url => 'https://10.0.0.11:6385',
:internal_url => 'https://10.0.0.11:6385' }
end
it { is_expected.to contain_keystone_endpoint('RegionOne/ironic').with(
:ensure => 'present',
:public_url => 'https://10.0.0.10:6385',
:admin_url => 'https://10.0.0.11:6385',
:internal_url => 'https://10.0.0.11:6385'
) }
end
describe 'with deprecated endpoint parameters' do
let :params do
{ :password => 'ironic_password',
:public_protocol => 'https',
:public_port => '80',
:public_address => '10.10.10.10',
:port => '81',
:internal_address => '10.10.10.11',
:admin_address => '10.10.10.12' }
end
it { is_expected.to contain_keystone_endpoint('RegionOne/ironic').with(
:ensure => 'present',
:public_url => "https://10.10.10.10:80",
:internal_url => "http://10.10.10.11:81",
:admin_url => "http://10.10.10.12:81"
) }
end
describe 'when overriding auth name' do
let :params do
{ :password => 'foo',
:auth_name => 'ironicy' }
end
it { is_expected.to contain_keystone_user('ironicy') }
it { is_expected.to contain_keystone_user_role('ironicy@services') }
it { is_expected.to contain_keystone_service('ironicy') }
it { is_expected.to contain_keystone_endpoint('RegionOne/ironicy') }
end
describe 'when overriding service name' do
let :params do
{
:service_name => 'ironic_service',
:password => 'ironic_password',
}
end
it { is_expected.to contain_keystone_user('ironic') }
it { is_expected.to contain_keystone_user_role('ironic@services') }
it { is_expected.to contain_keystone_service('ironic_service') }
it { is_expected.to contain_keystone_endpoint('RegionOne/ironic_service') }
end
describe 'when disabling user configuration' do
let :params do
{
:password => 'ironic_password',
:configure_user => false
}
end
it { is_expected.not_to contain_keystone_user('ironic') }
it { is_expected.to contain_keystone_user_role('ironic@services') }
it { is_expected.to contain_keystone_service('ironic').with(
:ensure => 'present',
:type => 'baremetal',
:description => 'Ironic Bare Metal Provisioning Service'
) }
end
describe 'when disabling user and user role configuration' do
let :params do
{
:password => 'ironic_password',
:configure_user => false,
:configure_user_role => false
}
end
it { is_expected.not_to contain_keystone_user('ironic') }
it { is_expected.not_to contain_keystone_user_role('ironic@services') }
it { is_expected.to contain_keystone_service('ironic').with(
:ensure => 'present',
:type => 'baremetal',
:description => 'Ironic Bare Metal Provisioning Service'
) }
end
end

View File

@ -1,41 +0,0 @@
require 'spec_helper'
describe 'ironic::policy' do
shared_examples_for 'ironic policies' do
let :params do
{
:policy_path => '/etc/ironic/policy.json',
:policies => {
'context_is_admin' => {
'key' => 'context_is_admin',
'value' => 'foo:bar'
}
}
}
end
it 'set up the policies' do
is_expected.to contain_openstacklib__policy__base('context_is_admin').with({
:key => 'context_is_admin',
:value => 'foo:bar'
})
end
end
context 'on Debian platforms' do
let :facts do
{ :osfamily => 'Debian' }
end
it_configures 'ironic policies'
end
context 'on RedHat platforms' do
let :facts do
{ :osfamily => 'RedHat' }
end
it_configures 'ironic policies'
end
end

View File

@ -1,5 +0,0 @@
shared_examples_for "a Puppet::Error" do |description|
it "with message matching #{description.inspect}" do
expect { is_expected.to have_class_count(1) }.to raise_error(Puppet::Error, description)
end
end

View File

@ -1,7 +0,0 @@
require 'puppetlabs_spec_helper/module_spec_helper'
require 'shared_examples'
RSpec.configure do |c|
c.alias_it_should_behave_like_to :it_configures, 'configures'
c.alias_it_should_behave_like_to :it_raises, 'raises'
end

View File

@ -1,56 +0,0 @@
require 'beaker-rspec'
require 'beaker/puppet_install_helper'
run_puppet_install_helper
RSpec.configure do |c|
# Project root
proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
modname = JSON.parse(open('metadata.json').read)['name'].split('-')[1]
# Readable test descriptions
c.formatter = :documentation
# Configure all nodes in nodeset
c.before :suite do
# Install module and dependencies
hosts.each do |host|
# install git
install_package host, 'git'
zuul_ref = ENV['ZUUL_REF']
zuul_branch = ENV['ZUUL_BRANCH']
zuul_url = ENV['ZUUL_URL']
repo = 'openstack/puppet-openstack-integration'
# Start out with clean moduledir, don't trust r10k to purge it
on host, "rm -rf /etc/puppet/modules/*"
# Install dependent modules via git or zuul
r = on host, "test -e /usr/zuul-env/bin/zuul-cloner", { :acceptable_exit_codes => [0,1] }
if r.exit_code == 0
zuul_clone_cmd = '/usr/zuul-env/bin/zuul-cloner '
zuul_clone_cmd += '--cache-dir /opt/git '
zuul_clone_cmd += "--zuul-ref #{zuul_ref} "
zuul_clone_cmd += "--zuul-branch #{zuul_branch} "
zuul_clone_cmd += "--zuul-url #{zuul_url} "
zuul_clone_cmd += "https://git.openstack.org #{repo}"
on host, zuul_clone_cmd
else
on host, "git clone https://git.openstack.org/#{repo} #{repo}"
end
on host, "ZUUL_REF=#{zuul_ref} ZUUL_BRANCH=#{zuul_branch} ZUUL_URL=#{zuul_url} bash #{repo}/install_modules.sh"
# Install the module being tested
on host, "rm -fr /etc/puppet/modules/#{modname}"
puppet_module_install(:source => proj_root, :module_name => modname)
on host, "rm -fr #{repo}"
# List modules installed to help with debugging
on host, puppet('module','list'), { :acceptable_exit_codes => 0 }
end
end
end

View File

@ -1,42 +0,0 @@
$LOAD_PATH.push(
File.join(
File.dirname(__FILE__),
'..',
'..',
'..',
'fixtures',
'modules',
'inifile',
'lib')
)
require 'spec_helper'
provider_class = Puppet::Type.type(:ironic_config).provider(:ini_setting)
describe provider_class do
it 'should default to the default setting when no other one is specified' do
resource = Puppet::Type::Ironic_config.new(
{
:name => 'DEFAULT/foo',
:value => 'bar'
}
)
provider = provider_class.new(resource)
expect(provider.section).to eq('DEFAULT')
expect(provider.setting).to eq('foo')
end
it 'should allow setting to be set explicitly' do
resource = Puppet::Type::Ironic_config.new(
{
:name => 'dude/foo',
:value => 'bar'
}
)
provider = provider_class.new(resource)
expect(provider.section).to eq('dude')
expect(provider.setting).to eq('foo')
end
end

View File

@ -1,111 +0,0 @@
require 'puppet'
require 'spec_helper'
require 'puppet/provider/ironic'
require 'tempfile'
describe Puppet::Provider::Ironic do
def klass
described_class
end
let :credential_hash do
{
'auth_host' => '192.168.56.210',
'auth_port' => '35357',
'auth_protocol' => 'https',
'admin_tenant_name' => 'admin_tenant',
'admin_user' => 'admin',
'admin_password' => 'password',
}
end
let :auth_endpoint do
'https://192.168.56.210:35357/v2.0/'
end
let :credential_error do
/Ironic types will not work/
end
after :each do
klass.reset
end
describe 'when determining credentials' do
it 'should fail if config is empty' do
conf = {}
klass.expects(:ironic_conf).returns(conf)
expect do
klass.ironic_credentials
end.to raise_error(Puppet::Error, credential_error)
end
it 'should fail if config does not have keystone_authtoken section.' do
conf = {'foo' => 'bar'}
klass.expects(:ironic_conf).returns(conf)
expect do
klass.ironic_credentials
end.to raise_error(Puppet::Error, credential_error)
end
it 'should fail if config does not contain all auth params' do
conf = {'keystone_authtoken' => {'invalid_value' => 'foo'}}
klass.expects(:ironic_conf).returns(conf)
expect do
klass.ironic_credentials
end.to raise_error(Puppet::Error, credential_error)
end
it 'should use specified host/port/protocol in the auth endpoint' do
conf = {'keystone_authtoken' => credential_hash}
klass.expects(:ironic_conf).returns(conf)
expect(klass.get_auth_endpoint).to eq(auth_endpoint)
end
end
describe 'when invoking the ironic cli' do
it 'should set auth credentials in the environment' do
authenv = {
:OS_AUTH_URL => auth_endpoint,
:OS_USERNAME => credential_hash['admin_user'],
:OS_TENANT_NAME => credential_hash['admin_tenant_name'],
:OS_PASSWORD => credential_hash['admin_password'],
}
klass.expects(:get_ironic_credentials).with().returns(credential_hash)
klass.expects(:withenv).with(authenv)
klass.auth_ironic('test_retries')
end
['[Errno 111] Connection refused',
'(HTTP 400)'].reverse.each do |valid_message|
it "should retry when ironic cli returns with error #{valid_message}" do
klass.expects(:get_ironic_credentials).with().returns({})
klass.expects(:sleep).with(10).returns(nil)
klass.expects(:ironic).twice.with(['test_retries']).raises(
Exception, valid_message).then.returns('')
klass.auth_ironic('test_retries')
end
end
end
describe 'when listing ironic resources' do
it 'should exclude the column header' do
output = <<-EOT
id
net1
net2
EOT
klass.expects(:auth_ironic).returns(output)
result = klass.list_ironic_resources('foo')
expect(result).to eql(['net1', 'net2'])
end
end
end

View File

@ -1,19 +0,0 @@
require 'puppet'
require 'puppet/type/ironic_config'
describe 'Puppet::Type.type(:ironic_config)' do
before :each do
@ironic_config = Puppet::Type.type(:ironic_config).new(:name => 'DEFAULT/foo', :value => 'bar')
end
it 'should autorequire the package that install the file' do
catalog = Puppet::Resource::Catalog.new
package = Puppet::Type.type(:package).new(:name => 'ironic-common')
catalog.add_resource package, @ironic_config
dependency = @ironic_config.autorequire
expect(dependency.size).to eq(1)
expect(dependency[0].target).to eq(@ironic_config)
expect(dependency[0].source).to eq(package)
end
end

Some files were not shown because too many files have changed in this diff Show More