opnsense-src/libexec/nuageinit/tests/nuageinit.sh
Baptiste Daroussin 16a6da44e2 nuageinit: add basic support for cloudinit.
this is a very early script to support cloudinit, it does not intend to
be a full featured cloudinit client, but will support a good enough
subset to be viable in most case.

It support nocloud and openstack config-2 config drive mode (iso9660 or
msdosfs)

The following features are currently supported:
- adding users (including a default user named 'freebsd' with password
  'freebsd'
- adding groups
- adding ssh keys
- static ipv4, static ipv6, dynamic ipv4

With this one is able to use the 'bring your own image feature" out of
box.

It is expected that the script grows the support of other clouds
supporting cloud-init, contributions are welcomed.

It is designed to be only run once via the firstboot mecanism.

Sponsored by:	OVHCloud
Differential Revision:	https://reviews.freebsd.org/D44141

(cherry picked from commit a42d6f76018e4ed8324e319ab48aac904bda437c)
(cherry picked from commit c051f22bce42d920abba61bd7cf4ef5b6a270ffa)
(cherry picked from commit b8c053c9a612651d4909f7a323088f3e92485b7b)
(cherry picked from commit 9eae9233fdcc946945f4191e1413f548adfa2943)
2024-04-11 13:52:52 +02:00

338 lines
9.4 KiB
Bash

atf_test_case args
atf_test_case nocloud
atf_test_case nocloud_userdata_script
atf_test_case nocloud_userdata_cloudconfig
atf_test_case nocloud_userdata_cloudconfig_users
atf_test_case nocloud_network
atf_test_case config2
atf_test_case config2_pubkeys
atf_test_case config2_network
atf_test_case config2_network_static_v4
args_body()
{
atf_check -s exit:1 -e inline:"Usage /usr/libexec/nuageinit <cloud-init directory> [config-2|nocloud]\n" /usr/libexec/nuageinit
atf_check -s exit:1 -e inline:"Usage /usr/libexec/nuageinit <cloud-init directory> [config-2|nocloud]\n" /usr/libexec/nuageinit bla
atf_check -s exit:1 -e inline:"Usage /usr/libexec/nuageinit <cloud-init directory> [config-2|nocloud]\n" /usr/libexec/nuageinit bla meh plop
atf_check -s exit:1 -e inline:"Unknown cloud init type: meh\n" /usr/libexec/nuageinit bla meh
}
nocloud_body()
{
here=$(pwd)
mkdir -p media/nuageinit
atf_check -s exit:1 -e match:"nuageinit: error parsing nocloud.*" /usr/libexec/nuageinit ${here}/media/nuageinit/ nocloud
export NUAGE_FAKE_ROOTDIR=$(pwd)
printf "instance-id: iid-local01\nlocal-hostname: cloudimg\n" > ${here}/media/nuageinit/meta-data
atf_check -s exit:0 /usr/libexec/nuageinit ${here}/media/nuageinit nocloud
atf_check -o inline:"hostname=\"cloudimg\"\n" cat etc/rc.conf.d/hostname
cat > media/nuageinit/meta-data << EOF
instance-id: iid-local01
hostname: myhost
EOF
atf_check -s exit:0 /usr/libexec/nuageinit ${here}/media/nuageinit nocloud
atf_check -o inline:"hostname=\"myhost\"\n" cat etc/rc.conf.d/hostname
}
nocloud_userdata_script_body()
{
here=$(pwd)
mkdir -p media/nuageinit
printf "instance-id: iid-local01\n" > ${here}/media/nuageinit/meta-data
printf "#!/bin/sh\necho "yeah"\n" > ${here}/media/nuageinit/user-data
chmod 755 ${here}/media/nuageinit/user-data
atf_check -s exit:0 -o inline:"yeah\n" /usr/libexec/nuageinit ${here}/media/nuageinit nocloud
}
nocloud_userdata_cloudconfig_users_body()
{
here=$(pwd)
export NUAGE_FAKE_ROOTDIR=$(pwd)
if [ $(id -u) -ne 0 ]; then
atf_skip "root required"
fi
mkdir -p media/nuageinit
printf "instance-id: iid-local01\n" > ${here}/media/nuageinit/meta-data
mkdir -p etc
cat > etc/master.passwd <<EOF
root:*:0:0::0:0:Charlie &:/root:/bin/csh
sys:*:1:0::0:0:Sys:/home/sys:/bin/csh
EOF
pwd_mkdb -d etc ${here}/etc/master.passwd
cat > etc/group <<EOF
wheel:*:0:root
users:*:1:
EOF
cat > media/nuageinit/user-data <<EOF
#cloud-config
groups:
- admingroup: [root,sys]
- cloud-users
users:
- default
- name: foobar
gecos: Foo B. Bar
primary_group: foobar
groups: users
passwd: $6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/
EOF
atf_check /usr/libexec/nuageinit ${here}/media/nuageinit nocloud
cat > expectedgroup << EOF
wheel:*:0:root,freebsd
users:*:1:foobar
admingroup:*:1001:root,sys
cloud-users:*:1002:
freebsd:*:1003:
foobar:*:1004:
EOF
cat > expectedpasswd << EOF
root:*:0:0::0:0:Charlie &:/root:/bin/csh
sys:*:1:0::0:0:Sys:/home/sys:/bin/csh
freebsd:freebsd:1001:1003::0:0:FreeBSD User:/home/freebsd:/bin/sh
foobar:H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/:1002:1004::0:0:Foo B. Bar:/home/foobar:/bin/sh
EOF
atf_check -o file:expectedpasswd cat ${here}/etc/master.passwd
atf_check -o file:expectedgroup cat ${here}/etc/group
}
nocloud_network_body()
{
here=$(pwd)
mkdir -p media/nuageinit
mkdir -p etc
cat > etc/master.passwd <<EOF
root:*:0:0::0:0:Charlie &:/root:/bin/csh
sys:*:1:0::0:0:Sys:/home/sys:/bin/csh
EOF
pwd_mkdb -d etc ${here}/etc/master.passwd
cat > etc/group <<EOF
wheel:*:0:root
users:*:1:
EOF
if [ $(id -u) -ne 0 ]; then
atf_skip "root required"
fi
mynetworks=$(ifconfig -l ether)
if [ -z "$mynetworks" ]; then
atf_skip "a network interface is needed"
fi
set -- $mynetworks
myiface=$1
myaddr=$(ifconfig $myiface ether | awk '/ether/ { print $2 }')
printf "instance-id: iid-local01\n" > ${here}/media/nuageinit/meta-data
cat > media/nuageinit/user-data <<EOF
#cloud-config
#
network:
version: 2
ethernets:
# opaque ID for physical interfaces, only referred to by other stanzas
id0:
match:
macaddress: '${myaddr}'
addresses:
- 192.168.14.2/24
- 2001:1::1/64
gateway4: 192.168.14.1
gateway6: 2001:1::2
EOF
export NUAGE_FAKE_ROOTDIR=$(pwd)
atf_check /usr/libexec/nuageinit ${here}/media/nuageinit nocloud
cat > network <<EOF
ifconfig_${myiface}="inet 192.168.14.2/24"
ifconfig_${myiface}_ipv6="inet6 2001:1::1/64"
ipv6_network_interfaces="${myiface}"
ipv6_default_interface="${myiface}"
EOF
cat > routing <<EOF
defaultrouter="192.168.14.1"
ipv6_defaultrouter="2001:1::2"
ipv6_route_${myiface}="2001:1::2 -prefixlen 128 -interface ${myiface}"
EOF
atf_check -o file:network cat ${here}/etc/rc.conf.d/network
atf_check -o file:routing cat ${here}/etc/rc.conf.d/routing
}
config2_body()
{
here=$(pwd)
mkdir -p media/nuageinit
atf_check -s exit:1 -e match:"nuageinit: error parsing config-2: meta_data.json.*" /usr/libexec/nuageinit ${here}/media/nuageinit config-2
printf "{}" > media/nuageinit/meta_data.json
atf_check /usr/libexec/nuageinit ${here}/media/nuageinit config-2
cat > media/nuageinit/meta_data.json << EOF
{
"hostname": "cloudimg",
}
EOF
export NUAGE_FAKE_ROOTDIR=$(pwd)
atf_check /usr/libexec/nuageinit ${here}/media/nuageinit config-2
atf_check -o inline:"hostname=\"cloudimg\"\n" cat etc/rc.conf.d/hostname
}
config2_pubkeys_body()
{
here=$(pwd)
if [ $(id -u) -ne 0 ]; then
atf_skip "root required"
fi
mkdir -p media/nuageinit
cat > media/nuageinit/meta_data.json << EOF
{
"public_keys": {
"mykey": "ssh-rsa AAAAB3NzaC1y...== Generated by Nova"
},
}
EOF
mkdir -p etc
cat > etc/master.passwd <<EOF
root:*:0:0::0:0:Charlie &:/root:/bin/csh
sys:*:1:0::0:0:Sys:/home/sys:/bin/csh
EOF
pwd_mkdb -d etc ${here}/etc/master.passwd
cat > etc/group <<EOF
wheel:*:0:root
users:*:1:
EOF
export NUAGE_FAKE_ROOTDIR=$(pwd)
atf_check /usr/libexec/nuageinit ${here}/media/nuageinit config-2
atf_check -o inline:"ssh-rsa AAAAB3NzaC1y...== Generated by Nova\n" cat home/freebsd/.ssh/authorized_keys
}
config2_network_body() {
here=$(pwd)
mkdir -p media/nuageinit
printf "{}" > media/nuageinit/meta_data.json
mynetworks=$(ifconfig -l ether)
if [ -z "$mynetworks" ]; then
atf_skip "a network interface is needed"
fi
set -- $mynetworks
myiface=$1
myaddr=$(ifconfig $myiface ether | awk '/ether/ { print $2 }')
cat > media/nuageinit/network_data.json <<EOF
{
"links": [
{
"ethernet_mac_address": "$myaddr",
"id": "iface0",
"mtu": null,
}
],
"networks": [
{
"id": "network0",
"link": "iface0",
"type": "ipv4_dhcp"
},
{ // IPv6
"id": "private-ipv4",
"type": "ipv6",
"link": "iface0",
// supports condensed IPv6 with CIDR netmask
"ip_address": "2001:cdba::3257:9652/24",
"gateway": "fd00::1"
"routes": [
{
"network": "::",
"netmask": "::",
"gateway": "fd00::1"
},
{
"network": "::",
"netmask": "ffff:ffff:ffff::",
"gateway": "fd00::1:1"
},
],
"network_id": "da5bb487-5193-4a65-a3df-4a0055a8c0d8"
},
],
}
EOF
export NUAGE_FAKE_ROOTDIR=$(pwd)
atf_check /usr/libexec/nuageinit ${here}/media/nuageinit config-2
cat > network <<EOF
ifconfig_${myiface}="DHCP"
ifconfig_${myiface}_ipv6="inet6 2001:cdba::3257:9652/24"
ipv6_network_interfaces="${myiface}"
ipv6_default_interface="${myiface}"
EOF
cat > routing <<EOF
ipv6_defaultrouter="fd00::1"
ipv6_route_${myiface}="fd00::1 -prefixlen 128 -interface ${myiface}"
ipv6_static_routes="${myiface}"
EOF
atf_check -o file:network cat ${here}/etc/rc.conf.d/network
atf_check -o file:routing cat ${here}/etc/rc.conf.d/routing
}
config2_network_static_v4_body() {
here=$(pwd)
mkdir -p media/nuageinit
printf "{}" > media/nuageinit/meta_data.json
mynetworks=$(ifconfig -l ether)
if [ -z "$mynetworks" ]; then
atf_skip "a network interface is needed"
fi
set -- $mynetworks
myiface=$1
myaddr=$(ifconfig $myiface ether | awk '/ether/ { print $2 }')
cat > media/nuageinit/network_data.json <<EOF
{
"links": [
{
"ethernet_mac_address": "$myaddr",
"id": "iface0",
"mtu": null,
}
],
"networks": [
{
"id": "network0",
"link": "iface0",
"type": "ipv4"
"ip_address": "10.184.0.244",
"netmask": "255.255.240.0",
"routes": [
{
"network": "10.0.0.0",
"netmask": "255.0.0.0",
"gateway": "11.0.0.1"
},
{
"network": "0.0.0.0",
"netmask": "0.0.0.0",
"gateway": "23.253.157.1"
}
]
}
]
}
EOF
export NUAGE_FAKE_ROOTDIR=$(pwd)
atf_check /usr/libexec/nuageinit ${here}/media/nuageinit config-2
cat > network <<EOF
ifconfig_${myiface}="inet 10.184.0.244 netmask 255.255.240.0"
EOF
cat > routing <<EOF
route_cloudinit1_${myiface}="-net 10.0.0.0 11.0.0.1 255.0.0.0"
defaultrouter="23.253.157.1"
static_routes="cloudinit1_${myiface}"
EOF
atf_check -o file:network cat ${here}/etc/rc.conf.d/network
atf_check -o file:routing cat ${here}/etc/rc.conf.d/routing
}
atf_init_test_cases()
{
atf_add_test_case args
atf_add_test_case nocloud
atf_add_test_case nocloud_userdata_script
atf_add_test_case nocloud_userdata_cloudconfig_users
atf_add_test_case nocloud_network
atf_add_test_case config2
atf_add_test_case config2_pubkeys
atf_add_test_case config2_network
atf_add_test_case config2_network_static_v4
}