1#!/usr/bin/env python3
2# This file is part of pycloudlib. See LICENSE file for license information.
3"""Basic examples of various lifecycle with a LXD instance."""
4
5import logging
6import textwrap
7
8import pycloudlib
9from pycloudlib.cloud import ImageType
10
11RELEASE = "noble"
12
13
14def snapshot_instance():
15 """Demonstrate snapshot functionality.
16
17 This shows the lifecycle of booting an instance and cleaning it
18 before creating a snapshot.
19
20 Next, both create the snapshot and immediately restore the original
21 instance to the snapshot level.
22 Finally, launch another instance from the snapshot of the instance.
23 """
24 with pycloudlib.LXDContainer("example-snapshot") as lxd:
25 with lxd.launch(name="pycloudlib-snapshot-base", image_id=RELEASE) as inst:
26 inst.wait()
27 snapshot_name = "snapshot"
28 inst.local_snapshot(snapshot_name)
29 inst.restore(snapshot_name)
30
31 child = lxd.clone(
32 "%s/%s" % (inst.name, snapshot_name),
33 "pycloudlib-snapshot-child",
34 )
35
36 child.delete()
37 inst.delete_snapshot(snapshot_name)
38 inst.delete(wait=False)
39
40
41def image_snapshot_instance(ephemeral_instance=False):
42 """Demonstrate image snapshot functionality.
43
44 Create an snapshot image from a running instance an show
45 how to launch a new instance based of this image snapshot
46 """
47 with pycloudlib.LXDContainer("example-image-snapshot") as lxd:
48 with lxd.launch(
49 name="pycloudlib-snapshot-base",
50 image_id=RELEASE,
51 ephemeral=ephemeral_instance,
52 ) as inst:
53 inst.wait()
54 inst.execute("touch snapshot-test.txt")
55 print("Base instance output: {}".format(inst.execute("ls")))
56 snapshot_image = lxd.snapshot(instance=inst)
57
58 with lxd.launch(
59 name="pycloudlib-snapshot-image",
60 image_id=snapshot_image,
61 ephemeral=ephemeral_instance,
62 ) as snapshot_inst:
63 print("Snapshot instance output: {}".format(snapshot_inst.execute("ls")))
64
65
66def modify_instance():
67 """Demonstrate how to modify and interact with an instance.
68
69 The inits an instance and before starting it, edits the the
70 container configuration.
71
72 Once started the instance demonstrates some interactions with the
73 instance.
74 """
75 with pycloudlib.LXDContainer("example-modify") as lxd:
76 with lxd.init("pycloudlib-modify-inst", RELEASE) as inst:
77 inst.edit("limits.memory", "3GB")
78 inst.start()
79
80 inst.execute("uptime > /tmp/uptime")
81 inst.pull_file("/tmp/uptime", "/tmp/pulled_file")
82 inst.push_file("/tmp/pulled_file", "/tmp/uptime_2")
83 inst.execute("cat /tmp/uptime_2")
84
85
86def launch_multiple():
87 """Launch multiple instances.
88
89 How to quickly launch multiple instances with LXD. This prevents
90 waiting for the instance to start each time. Note that the
91 wait_for_delete method is not used, as LXD does not do any waiting.
92 """
93 lxd = pycloudlib.LXDContainer("example-multiple")
94
95 instances = []
96 for num in range(2):
97 inst = lxd.launch(name="pycloudlib-%s" % num, image_id=RELEASE)
98 instances.append(inst)
99
100 for instance in instances:
101 instance.wait()
102
103 # Launch daily minimal images
104 image_id = lxd.daily_image(release=RELEASE, image_type=ImageType.MINIMAL)
105 inst = lxd.launch(name="pycloudlib-minimal", image_id=image_id)
106 instances.append(inst)
107
108 for instance in instances:
109 instance.delete()
110
111
112def launch_options():
113 """Demonstrate various launching scenarios.
114
115 First up is launching with a different profile, in this case with
116 two profiles.
117
118 Next, is launching an ephemeral instance with a different image
119 remote server.
120
121 Then, an instance with custom network, storage, and type settings.
122 This is an example of booting an instance without cloud-init so
123 wait is set to False.
124
125 Finally, an instance with custom configurations options.
126 """
127 lxd = pycloudlib.LXDContainer("example-launch")
128 kvm_profile = textwrap.dedent(
129 """\
130 devices:
131 kvm:
132 path: /dev/kvm
133 type: unix-char
134 """
135 )
136
137 lxd.create_profile(profile_name="kvm", profile_config=kvm_profile)
138
139 lxd.launch(
140 name="pycloudlib-kvm",
141 image_id=RELEASE,
142 profile_list=["default", "kvm"],
143 )
144 lxd.delete_instance("pycloudlib-kvm")
145
146 lxd.launch(
147 name="pycloudlib-ephemeral",
148 image_id="ubuntu:%s" % RELEASE,
149 ephemeral=True,
150 )
151 lxd.delete_instance("pycloudlib-ephemeral")
152
153 lxd.launch(
154 name="pycloudlib-custom-hw",
155 image_id="images:ubuntu/xenial",
156 network="lxdbr0",
157 storage="default",
158 inst_type="t2.micro",
159 wait=False,
160 )
161 lxd.delete_instance("pycloudlib-custom-hw")
162
163 lxd.launch(
164 name="pycloudlib-privileged",
165 image_id=RELEASE,
166 config_dict={
167 "security.nesting": "true",
168 "security.privileged": "true",
169 },
170 )
171 lxd.delete_instance("pycloudlib-privileged")
172
173
174def basic_lifecycle():
175 """Demonstrate basic set of lifecycle operations with LXD."""
176 with pycloudlib.LXDContainer("example-basic") as lxd:
177 with lxd.launch(image_id=RELEASE) as inst:
178 inst.wait()
179
180 name = "pycloudlib-daily"
181 with lxd.launch(name=name, image_id=RELEASE) as inst:
182 inst.wait()
183 inst.console_log()
184
185 result = inst.execute("uptime")
186 print(result)
187 print(result.return_code)
188 print(result.ok)
189 print(result.failed)
190 print(bool(result))
191
192 inst.shutdown()
193 inst.start()
194 inst.restart()
195
196 # Custom attributes
197 print(inst.ephemeral)
198 print(inst.state)
199
200 same_instance_retrieved = lxd.get_instance(name)
201 same_instance_retrieved.delete()
202
203
204def launch_virtual_machine():
205 """Demonstrate launching virtual machine scenario."""
206 with pycloudlib.LXDVirtualMachine("example-vm") as lxd:
207 pub_key_path = "lxd-pubkey"
208 priv_key_path = "lxd-privkey"
209 pub_key, priv_key = lxd.create_key_pair()
210
211 with open(pub_key_path, "w", encoding="utf-8") as f:
212 f.write(pub_key)
213
214 with open(priv_key_path, "w", encoding="utf-8") as f:
215 f.write(priv_key)
216
217 lxd.use_key(public_key_path=pub_key_path, private_key_path=priv_key_path)
218
219 image_id = lxd.released_image(release=RELEASE)
220 image_serial = lxd.image_serial(image_id)
221 print("Image serial: {}".format(image_serial))
222 name = "pycloudlib-vm"
223 with lxd.launch(name=name, image_id=image_id) as inst:
224 inst.wait()
225 print("Is vm: {}".format(inst.is_vm))
226 result = inst.execute("lsb_release -a")
227 print(result)
228 print(result.return_code)
229 print(result.ok)
230 print(result.failed)
231 print(bool(result))
232
233 inst_2 = lxd.get_instance(name)
234 print(inst_2.execute("lsb_release -a"))
235
236 inst.shutdown()
237 inst.start()
238 inst.restart()
239
240
241def demo():
242 """Show examples of using the LXD library."""
243 basic_lifecycle()
244 launch_options()
245 launch_multiple()
246 modify_instance()
247 snapshot_instance()
248 image_snapshot_instance(ephemeral_instance=False)
249 launch_virtual_machine()
250
251
252if __name__ == "__main__":
253 logging.basicConfig(level=logging.DEBUG)
254 demo()