1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
|
#!/bin/bash
set -f
CONTAINER_NAME=""
VERBOSITY=0
TEMP_D=""
error() { echo "$@" 1>&2; }
fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
Usage() {
cat <<EOF
Usage: ${0##*/} [ options ] release name
create a container 'name' with proposed and provided packages.
options:
-i | --install PKGLIST install these packages.
-u | --upgrade PKGLIST update the packages in PKGLIST
either ',' or space delimited
special 'all' means all.
default is 'cloud-init'
-A | --add-archive A add the apt archive via 'apt-add-repository'
-p | --publish publish the result as an image named 'name'
-P | --proposed enable proposed
EOF
}
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; return 1; }
cleanup() {
[ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
if [ -n "$CONTAINER_NAME" ]; then
lxc delete --force "$CONTAINER_NAME"
CONTAINER_NAME=""
fi
}
debug() {
local level=${1}; shift;
[ "${level}" -gt "${VERBOSITY}" ] && return
error "${@}"
}
enable_proposed() {
local rel="" line=""
rel=$(lsb_release -sc)
line=$(awk '$1 == "deb" && $2 ~ /ubuntu.com/ {
printf("%s %s %s-proposed main universe\n", $1, $2, rel); exit(0) };
' "rel=$rel" /etc/apt/sources.list)
echo "$line" > "/etc/apt/sources.list.d/proposed.list" ||
{ error "failed enabling proposed with '$line'"; return 1; }
}
add_archives() {
local debline="" rel="$(lsb_release -sc)"
for debline in "$@"; do
debug 1 "enabling $debline"
debline=$(echo "$debline" | sed "s,RELEASE,$rel,")
apt-add-repository -y "$debline" || return
done
}
chrooted() {
local short_opts="aA:hiPu:v"
local long_opts="add-archive:,help,install:,proposed,proxy:,upgrade:,verbose"
local getopt_out=""
getopt_out=$(getopt --name "${0##*/}" \
--options "${short_opts}" --long "${long_opts}" -- "$@") &&
eval set -- "${getopt_out}" ||
{ bad_Usage; return; }
local cur="" next=""
local upgrade="cloud-init" install="" proposed="false" archives=""
archives=( )
echo "$*"
while [ $# -ne 0 ]; do
cur="$1"; next="$2";
case "$cur" in
-A|--add-archive) archives[${#archives[@]}]="$next"; shift;;
-h|--help) Usage ; exit 0;;
-P|--proposed) proposed=true;;
--proxy) proxy=$next; shift;;
-u|--upgrade)
if [ "$next" = "" -o "$next" = "none" ]; then
upgrade=""
else
upgrade="${upgrade:+${upgrade},}$next";
fi
shift;;
-i|--install) install=${install:+${install},}$next; shift;;
-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
--) shift; break;;
esac
shift;
done
upgrade=$(echo "$upgrade" | sed 's/,//g')
install=$(echo "$install" | sed 's/,//g')
export http_proxy=${proxy}
if [ "$proposed" = "true" ]; then
enable_proposed || return
fi
add_archives "${archives[@]}" || return
apt-get update -q || return
export DEBIAN_FRONTEND=noninteractive
if [ -n "$install" ]; then
debug 1 "installing: $install"
apt-get install --quiet --assume-yes $install </dev/null || return
fi
if [ -n "$upgrade" -a "$upgrade" != "all" ]; then
debug 1 "upgrading: $upgrade"
apt-get install --quiet --assume-yes --only-upgrade \
$upgrade </dev/null || return
elif [ "$upgrade" = "all" ]; then
debug 1 "dist-upgrading"
apt-get dist-upgrade --quiet --assume-yes </dev/null || return
fi
return 0
}
main() {
local short_opts="aA:hiPpu:v"
local long_opts="add-archive:,help,install:,proposed,proxy:,publish,upgrade:,verbose"
local getopt_out=""
getopt_out=$(getopt --name "${0##*/}" \
--options "${short_opts}" --long "${long_opts}" -- "$@") &&
eval set -- "${getopt_out}" ||
{ bad_Usage; return; }
local cur="" next="" publish="false" vflag="" pt="" proxy="${http_proxy}"
pt=( ) # pass through
while [ $# -ne 0 ]; do
cur="$1"; next="$2";
case "$cur" in
# any key=value passthrough
-A|--add-archive|-u|--upgrade|-i|--install|--proxy)
pt=( "${pt[@]}" "$cur" "$next" ); shift;;
# any flag pass through.
-P|--proposed) pt[${#pt[@]}]="$cur";;
-p|--publish) publish=true;;
-h|--help) Usage ; exit 0;;
-v|--verbose) VERBOSITY=$((${VERBOSITY}+1))
vflag="${vflag:--}v";;
--) shift; break;;
esac
shift;
done
[ $# -eq 0 ] && { bad_Usage "must provide release and name."; return 1; }
[ $# -eq 2 ] || { bad_Usage "Expected 2 args, got $# ($*)"; return; }
local release="$1" cname="$2" pubname="" clean=""
local src="ubuntu-daily:$release"
clean="$cname"
if [ "$publish" = "true" ]; then
pubname="$cname"
cname="${cname}-${RANDOM}${RANDOM}"
clean="$cname"
fi
trap cleanup EXIT
debug 1 "initializing container $cname"
lxc init "$src" "$cname" || {
error "failed to create $cname from $src"
return
}
CONTAINER_NAME="$clean"
local lxc_ver="" cmd=""
lxc_ver=$(lxc --version)
if dpkg --compare-versions $lxc_ver ge 2.17; then
cmd=( lxc-pstart "$cname" -- )
else
# avoid sudo prompt by following doc at:
# https://gist.github.com/smoser/e7d368481687ab39dc08#file-mic-lxd
cmd=( sudo mount-image-callback "lxd:$cname" --system-resolvconf
mchroot -- )
fi
"${cmd[@]}" /bin/bash -s chrooted "$vflag" "${pt[@]}" < "$0" ||
return
if [ "$publish" = "true" ]; then
debug 1 "publishing $cname to alias $pubname"
lxc publish "$cname" local: "--alias=$pubname"
else
CONTAINER_NAME=""
fi
return 0
}
if [ "$1" = "chrooted" ]; then
shift
chrooted "$@"
else
main "$@"
fi
# vi: ts=4 expandtab
|