Skip to content

Commit 23ca5df

Browse files
authored
add YouCanBootAnythingAsLongAsItsAlpine image source (#975)
For development purposes, allow people to select the alpine.iso blob that ships with the propolis-server zone image as an image source. Update propolis to "no longer can we only boot alpine" rev. Add "How to provision an instance using the CLI" to how-to-run doc.
1 parent 74b68ef commit 23ca5df

File tree

7 files changed

+166
-6
lines changed

7 files changed

+166
-6
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/how-to-run.adoc

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,83 @@ unique local addresses in the subnet of the first Sled Agent: `fd00:1122:3344:1:
133133

134134
Note that Sled Agent runs in the global zone and is the one responsible for bringing up all the other
135135
other services and allocating them with vNICs and IPv6 addresses.
136+
137+
=== How to provision an instance using the CLI
138+
139+
Here are the current steps to provision an instance using the https://github.com/oxidecomputer/cli[oxide]
140+
command line interface.
141+
142+
1. Create an organization and project that the resources will live under:
143+
144+
oxide org create myorg
145+
oxide project create -o myorg myproj
146+
147+
2. Define a global image that will be used as initial disk contents. This can be the alpine.iso image that ships with propolis, or an ISO / raw disk image / etc hosted at a URL:
148+
149+
oxide api /images --method POST --input - <<EOF
150+
{
151+
"name": "alpine",
152+
"description": "boot from propolis zone blob!",
153+
"block_size": 512,
154+
"distribution": "alpine",
155+
"version": "propolis-blob",
156+
"source": {
157+
"type": "you_can_boot_anything_as_long_as_its_alpine"
158+
}
159+
}
160+
EOF
161+
162+
oxide api /images --method POST --input - <<EOF
163+
{
164+
"name": "crucible-tester-sparse",
165+
"description": "boot from a url!",
166+
"block_size": 512,
167+
"distribution": "debian",
168+
"version": "9",
169+
"source": {
170+
"type": "url",
171+
"url": "http://[fd00:1122:3344:101::15]/crucible-tester-sparse.img"
172+
}
173+
}
174+
EOF
175+
176+
3. Create a disk from that global image (note that disk size must be greater than or equal to image size!). The example below creates a disk using the image made from the alpine ISO that ships with propolis, and sets the size to be the exact same as the image size:
177+
178+
oxide api /organizations/myorg/projects/myproj/disks/ --method POST --input - <<EOF
179+
{
180+
"name": "alpine",
181+
"description": "alpine.iso blob",
182+
"block_size": 512,
183+
"size": $(oxide api /images/alpine | jq -r .size),
184+
"disk_source": {
185+
"type": "global_image",
186+
"image_id": "$(oxide api /images/alpine | jq -r .id)"
187+
}
188+
}
189+
EOF
190+
191+
4. Create an instance, attaching the disk created above:
192+
193+
oxide api /organizations/myorg/projects/myproj/instances --method POST --input - <<EOF
194+
{
195+
"name": "myinst",
196+
"description": "my inst",
197+
"hostname": "myinst",
198+
"memory": 1073741824,
199+
"ncpus": 2,
200+
"disks": [
201+
{
202+
"type": "attach",
203+
"name": "alpine"
204+
}
205+
]
206+
}
207+
EOF
208+
209+
5. Optionally, attach to the propolis server serial console:
210+
211+
a. find the zone launched for the instance: `zoneadm list -c | grep oxz_propolis-server`
212+
b. get the instance uuid from the zone name. if the zone's name is `oxz_propolis-server_3b03ad43-4e9b-4f3a-866c-238d9ec4ac45`, then the uuid is `3b03ad43-4e9b-4f3a-866c-238d9ec4ac45`
213+
c. find the propolis server listen address: `pfexec zlogin oxz_propolis-server_3b03ad43-4e9b-4f3a-866c-238d9ec4ac45 svccfg -s svc:/system/illumos/propolis-server:vm-3b03ad43-4e9b-4f3a-866c-238d9ec4ac45 listprop config/server_addr`
214+
d. build and launch propolis-cli, filling in values for IP and PORT based on the listen address: `./target/release/propolis-cli -s <IP> -p <PORT> serial`
215+

nexus/src/app/image.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,63 @@ impl super::Nexus {
203203
&"creating images from snapshots not supported",
204204
));
205205
}
206+
207+
params::ImageSource::YouCanBootAnythingAsLongAsItsAlpine => {
208+
// Each Propolis zone ships with an alpine.iso (it's part of the
209+
// package-manifest.toml blobs), and for development purposes
210+
// allow users to boot that. This should go away when that blob
211+
// does.
212+
let db_block_size = db::model::BlockSize::Traditional;
213+
let block_size: u64 = db_block_size.to_bytes() as u64;
214+
215+
let volume_construction_request = sled_agent_client::types::VolumeConstructionRequest::Volume {
216+
block_size,
217+
sub_volumes: vec![
218+
sled_agent_client::types::VolumeConstructionRequest::File {
219+
block_size,
220+
path: "/opt/oxide/propolis-server/blob/alpine.iso".into(),
221+
}
222+
],
223+
read_only_parent: None,
224+
};
225+
226+
let volume_data =
227+
serde_json::to_string(&volume_construction_request)?;
228+
229+
// Nexus runs in its own zone so we can't ask the propolis zone
230+
// image tar file for size of alpine.iso. Conservatively set the
231+
// size to 100M (at the time of this comment, it's 41M). Any
232+
// disk created from this image has to be larger than it.
233+
let size: u64 = 100 * 1024 * 1024;
234+
let size: external::ByteCount =
235+
size.try_into().map_err(|e| Error::InvalidValue {
236+
label: String::from("size"),
237+
message: format!("size is invalid: {}", e),
238+
})?;
239+
240+
let new_image_volume =
241+
db::model::Volume::new(Uuid::new_v4(), volume_data);
242+
let volume =
243+
self.db_datastore.volume_create(new_image_volume).await?;
244+
245+
db::model::GlobalImage {
246+
identity: db::model::GlobalImageIdentity::new(
247+
Uuid::new_v4(),
248+
params.identity.clone(),
249+
),
250+
volume_id: volume.id(),
251+
url: None,
252+
distribution: "alpine".parse().map_err(|_| {
253+
Error::internal_error(
254+
&"alpine is not a valid distribution?",
255+
)
256+
})?,
257+
version: "propolis-blob".into(),
258+
digest: None,
259+
block_size: db_block_size,
260+
size: size.into(),
261+
}
262+
}
206263
};
207264

208265
self.db_datastore.global_image_create_image(opctx, new_image).await

nexus/src/external_api/params.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,16 @@ pub struct NetworkInterfaceIdentifier {
390390
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
391391
#[serde(tag = "type", rename_all = "snake_case")]
392392
pub enum ImageSource {
393-
Url { url: String },
394-
Snapshot { id: Uuid },
393+
Url {
394+
url: String,
395+
},
396+
Snapshot {
397+
id: Uuid,
398+
},
399+
400+
/// Boot the Alpine ISO that ships with the Propolis zone. Intended for
401+
/// development purposes only.
402+
YouCanBootAnythingAsLongAsItsAlpine,
395403
}
396404

397405
/// OS image distribution

openapi/nexus.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6100,6 +6100,21 @@
61006100
"id",
61016101
"type"
61026102
]
6103+
},
6104+
{
6105+
"description": "Boot the Alpine ISO that ships with the Propolis zone. Intended for development purposes only.",
6106+
"type": "object",
6107+
"properties": {
6108+
"type": {
6109+
"type": "string",
6110+
"enum": [
6111+
"you_can_boot_anything_as_long_as_its_alpine"
6112+
]
6113+
}
6114+
},
6115+
"required": [
6116+
"type"
6117+
]
61036118
}
61046119
]
61056120
},

package-manifest.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ zone = true
9898
[external_package.propolis-server.source]
9999
type = "prebuilt"
100100
repo = "propolis"
101-
commit = "a11ccd5bf001e0c690c67d117f8beb06b0bc6914"
101+
commit = "1538f78c1656bd3ac8ef816f6177ae9b1bef348a"
102102
# The SHA256 digest is automatically posted to:
103103
# https://buildomat.eng.oxide.computer/public/file/oxidecomputer/propolis/image/<commit>/propolis-server.sha256.txt
104-
sha256 = "52dd465bf70f3130e16cfb32eefb87f5d01514f1f60a7dd9a1eca970a0669159"
104+
sha256 = "1e21d95a1254f6796a2a7fee3a49f14988beb5646505fc7c9d669ef49f6a50f3"

sled-agent/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ omicron-common = { path = "../common" }
2424
p256 = "0.9.0"
2525
percent-encoding = "2.1.0"
2626
progenitor = { git = "https://github.com/oxidecomputer/progenitor" }
27-
propolis-client = { git = "https://github.com/oxidecomputer/propolis", rev = "a11ccd5bf001e0c690c67d117f8beb06b0bc6914" }
27+
propolis-client = { git = "https://github.com/oxidecomputer/propolis", rev = "1538f78c1656bd3ac8ef816f6177ae9b1bef348a" }
2828
rand = { version = "0.8.5", features = ["getrandom"] }
2929
reqwest = { version = "0.11.8", default-features = false, features = ["rustls-tls", "stream"] }
3030
schemars = { version = "0.8.10", features = [ "chrono", "uuid1" ] }

0 commit comments

Comments
 (0)