1
1
// Copyright (c) Microsoft Corporation.
2
2
// Licensed under the MIT License.
3
3
4
+ //! This module provides functionality for handling media devices, including mounting,
5
+ //! unmounting, and reading [`OVF`] (Open Virtualization Format) environment data. It defines
6
+ //! the [`Media`] struct with state management for [`Mounted`] and [`Unmounted`] states, as well
7
+ //! as utility functions for parsing [`OVF`] environment data and retrieving mounted devices
8
+ //! with CDROM-type filesystems.
9
+ //!
10
+ //! # Overview
11
+ //!
12
+ //! The `media` module is designed to manage media devices in a cloud environment. It
13
+ //! includes functionality to mount and unmount media devices, read [`OVF`] environment data,
14
+ //! and parse the data into structured formats. This is particularly useful for provisioning
15
+ //! virtual machines with specific configurations.
16
+ //!
17
+ //! # Key Components
18
+ //!
19
+ //! - [`Media`]: A struct representing a media device, with state management for [`Mounted`] and [`Unmounted`] states.
20
+ //! - [`Mounted`] and [`Unmounted`]: Zero-sized structs used to indicate the state of a [`Media`] instance.
21
+ //! - [`parse_ovf_env`]: A function to parse [`OVF`] environment data from a string.
22
+ //! - [`mount_parse_ovf_env`]: A function to mount a media device, read its [`OVF`] environment data, and return the parsed data.
23
+ //! - [`get_mount_device`]: A function to retrieve a list of mounted devices with CDROM-type filesystems.
24
+ //!
25
+ //! [`Media`]: struct.Media.html
26
+ //! [`Mounted`]: struct.Mounted.html
27
+ //! [`Unmounted`]: struct.Unmounted.html
28
+ //! [`parse_ovf_env`]: fn.parse_ovf_env.html
29
+ //! [`mount_parse_ovf_env`]: fn.mount_parse_ovf_env.html
30
+ //! [`get_mount_device`]: fn.get_mount_device.html
31
+ //! [`OVF`]: https://www.dmtf.org/standards/ovf
32
+
4
33
use std:: fs;
5
34
use std:: fs:: create_dir_all;
6
35
use std:: fs:: File ;
@@ -19,6 +48,11 @@ use tracing::instrument;
19
48
use crate :: error:: Error ;
20
49
use fstab:: FsTab ;
21
50
51
+ /// Represents a media device.
52
+ ///
53
+ /// # Type Parameters
54
+ ///
55
+ /// * `State` - The state of the media, either `Mounted` or `Unmounted`.
22
56
#[ derive( Debug , Default , Deserialize , PartialEq , Clone ) ]
23
57
pub struct Environment {
24
58
#[ serde( rename = "ProvisioningSection" ) ]
@@ -27,6 +61,7 @@ pub struct Environment {
27
61
pub platform_settings_section : PlatformSettingsSection ,
28
62
}
29
63
64
+ /// Provisioning section of the environment configuration.
30
65
#[ derive( Debug , Default , Deserialize , PartialEq , Clone ) ]
31
66
pub struct ProvisioningSection {
32
67
#[ serde( rename = "Version" ) ]
@@ -35,6 +70,7 @@ pub struct ProvisioningSection {
35
70
pub linux_prov_conf_set : LinuxProvisioningConfigurationSet ,
36
71
}
37
72
73
+ /// Linux provisioning configuration set.
38
74
#[ derive( Debug , Default , Deserialize , PartialEq , Clone ) ]
39
75
pub struct LinuxProvisioningConfigurationSet {
40
76
#[ serde( rename = "UserName" ) ]
@@ -45,6 +81,7 @@ pub struct LinuxProvisioningConfigurationSet {
45
81
pub hostname : String ,
46
82
}
47
83
84
+ /// Platform settings section of the environment configuration.
48
85
#[ derive( Debug , Default , Deserialize , PartialEq , Clone ) ]
49
86
pub struct PlatformSettingsSection {
50
87
#[ serde( rename = "Version" ) ]
@@ -53,6 +90,7 @@ pub struct PlatformSettingsSection {
53
90
pub platform_settings : PlatformSettings ,
54
91
}
55
92
93
+ /// Platform settings details.
56
94
#[ derive( Debug , Default , Deserialize , PartialEq , Clone ) ]
57
95
pub struct PlatformSettings {
58
96
#[ serde( default = "default_preprov" , rename = "PreprovisionedVm" ) ]
@@ -61,25 +99,52 @@ pub struct PlatformSettings {
61
99
pub preprovisioned_vm_type : String ,
62
100
}
63
101
102
+ /// Returns an empty string as the default password.
103
+ ///
104
+ /// # Returns
105
+ ///
106
+ /// A `String` containing an empty password.
64
107
fn default_password ( ) -> String {
65
108
"" . to_owned ( )
66
109
}
67
110
111
+ /// Returns `false` as the default value for preprovisioned VM.
112
+ ///
113
+ /// # Returns
114
+ ///
115
+ /// A `bool` indicating that the VM is not preprovisioned.
68
116
fn default_preprov ( ) -> bool {
69
117
false
70
118
}
71
119
120
+ /// Returns "None" as the default type for preprovisioned VM.
121
+ ///
122
+ /// # Returns
123
+ ///
124
+ /// A `String` containing "None" as the default preprovisioned VM type.
72
125
fn default_preprov_type ( ) -> String {
73
126
"None" . to_owned ( )
74
127
}
75
128
129
+ /// Path to the default mount device.
76
130
pub const PATH_MOUNT_DEVICE : & str = "/dev/sr0" ;
131
+ /// Path to the default mount point.
77
132
pub const PATH_MOUNT_POINT : & str = "/run/azure-init/media/" ;
78
133
134
+ /// Valid filesystems for CDROM devices.
79
135
const CDROM_VALID_FS : & [ & str ] = & [ "iso9660" , "udf" ] ;
136
+ /// Path to the mount table file.
80
137
const MTAB_PATH : & str = "/etc/mtab" ;
81
138
82
- // Get a mounted device with any filesystem for CDROM
139
+ /// Retrieves a list of mounted devices with CDROM-type filesystems.
140
+ ///
141
+ /// # Arguments
142
+ ///
143
+ /// * `path` - Optional path to the mount table file.
144
+ ///
145
+ /// # Returns
146
+ ///
147
+ /// A `Result` containing a vector of device paths as strings, or an `Error`.
83
148
#[ instrument]
84
149
pub fn get_mount_device ( path : Option < & Path > ) -> Result < Vec < String > , Error > {
85
150
let fstab = FsTab :: new ( path. unwrap_or_else ( || Path :: new ( MTAB_PATH ) ) ) ;
@@ -100,12 +165,19 @@ pub fn get_mount_device(path: Option<&Path>) -> Result<Vec<String>, Error> {
100
165
Ok ( cdrom_devices)
101
166
}
102
167
103
- // Some zero-sized structs that just provide states for our state machine
168
+ /// Represents the state of a mounted media.
104
169
#[ derive( Debug ) ]
105
170
pub struct Mounted ;
171
+
172
+ /// Represents the state of an unmounted media.
106
173
#[ derive( Debug ) ]
107
174
pub struct Unmounted ;
108
175
176
+ /// Represents a media device.
177
+ ///
178
+ /// # Type Parameters
179
+ ///
180
+ /// * `State` - The state of the media, either `Mounted` or `Unmounted`.
109
181
#[ derive( Debug ) ]
110
182
pub struct Media < State = Unmounted > {
111
183
device_path : PathBuf ,
@@ -114,6 +186,16 @@ pub struct Media<State = Unmounted> {
114
186
}
115
187
116
188
impl Media < Unmounted > {
189
+ /// Creates a new `Media` instance.
190
+ ///
191
+ /// # Arguments
192
+ ///
193
+ /// * `device_path` - The path to the media device.
194
+ /// * `mount_path` - The path where the media will be mounted.
195
+ ///
196
+ /// # Returns
197
+ ///
198
+ /// A new `Media` instance in the `Unmounted` state.
117
199
pub fn new ( device_path : PathBuf , mount_path : PathBuf ) -> Media < Unmounted > {
118
200
Media {
119
201
device_path,
@@ -122,6 +204,11 @@ impl Media<Unmounted> {
122
204
}
123
205
}
124
206
207
+ /// Mounts the media device.
208
+ ///
209
+ /// # Returns
210
+ ///
211
+ /// A `Result` containing the `Media` instance in the `Mounted` state, or an `Error`.
125
212
#[ instrument]
126
213
pub fn mount ( self ) -> Result < Media < Mounted > , Error > {
127
214
create_dir_all ( & self . mount_path ) ?;
@@ -155,6 +242,11 @@ impl Media<Unmounted> {
155
242
}
156
243
157
244
impl Media < Mounted > {
245
+ /// Unmounts the media device.
246
+ ///
247
+ /// # Returns
248
+ ///
249
+ /// A `Result` indicating success or failure.
158
250
#[ instrument]
159
251
pub fn unmount ( self ) -> Result < ( ) , Error > {
160
252
let umount_status =
@@ -178,6 +270,11 @@ impl Media<Mounted> {
178
270
}
179
271
}
180
272
273
+ /// Reads the OVF environment data to a string.
274
+ ///
275
+ /// # Returns
276
+ ///
277
+ /// A `Result` containing the OVF environment data as a string, or an `Error`.
181
278
#[ instrument]
182
279
pub fn read_ovf_env_to_string ( & self ) -> Result < String , Error > {
183
280
let mut file_path = self . mount_path . clone ( ) ;
@@ -191,6 +288,50 @@ impl Media<Mounted> {
191
288
}
192
289
}
193
290
291
+ /// Parses the OVF environment data.
292
+ ///
293
+ /// # Arguments
294
+ ///
295
+ /// * `ovf_body` - A string slice containing the OVF environment data.
296
+ ///
297
+ /// # Returns
298
+ ///
299
+ /// A `Result` containing the parsed `Environment` struct, or an `Error`.
300
+ ///
301
+ /// # Example
302
+ ///
303
+ /// ```
304
+ /// use libazureinit::media::parse_ovf_env;
305
+ ///
306
+ /// // Example dummy OVF environment data
307
+ /// let ovf_body = r#"
308
+ /// <Environment xmlns="http://schemas.dmtf.org/ovf/environment/1">
309
+ /// <ProvisioningSection>
310
+ /// <Version>1.0</Version>
311
+ /// <LinuxProvisioningConfigurationSet>
312
+ /// <UserName>myusername</UserName>
313
+ /// <UserPassword></UserPassword>
314
+ /// <DisableSshPasswordAuthentication>false</DisableSshPasswordAuthentication>
315
+ /// <HostName>myhostname</HostName>
316
+ /// </LinuxProvisioningConfigurationSet>
317
+ /// </ProvisioningSection>
318
+ /// <PlatformSettingsSection>
319
+ /// <Version>1.0</Version>
320
+ /// <PlatformSettings>
321
+ /// <PreprovisionedVm>false</PreprovisionedVm>
322
+ /// <PreprovisionedVmType>None</PreprovisionedVmType>
323
+ /// </PlatformSettings>
324
+ /// </PlatformSettingsSection>
325
+ /// </Environment>
326
+ /// "#;
327
+ ///
328
+ /// let environment = parse_ovf_env(ovf_body).unwrap();
329
+ /// assert_eq!(environment.provisioning_section.linux_prov_conf_set.username, "myusername");
330
+ /// assert_eq!(environment.provisioning_section.linux_prov_conf_set.password, "");
331
+ /// assert_eq!(environment.provisioning_section.linux_prov_conf_set.hostname, "myhostname");
332
+ /// assert_eq!(environment.platform_settings_section.platform_settings.preprovisioned_vm, false);
333
+ /// assert_eq!(environment.platform_settings_section.platform_settings.preprovisioned_vm_type, "None");
334
+ /// ```
194
335
#[ instrument( skip_all) ]
195
336
pub fn parse_ovf_env ( ovf_body : & str ) -> Result < Environment , Error > {
196
337
let environment: Environment = from_str ( ovf_body) ?;
@@ -207,7 +348,15 @@ pub fn parse_ovf_env(ovf_body: &str) -> Result<Environment, Error> {
207
348
}
208
349
}
209
350
210
- // Mount the given device, get OVF environment data, return it.
351
+ /// Mounts the given device, gets OVF environment data, and returns it.
352
+ ///
353
+ /// # Arguments
354
+ ///
355
+ /// * `dev` - A string containing the device path.
356
+ ///
357
+ /// # Returns
358
+ ///
359
+ /// A `Result` containing the parsed `Environment` struct, or an `Error`.
211
360
#[ instrument( skip_all) ]
212
361
pub fn mount_parse_ovf_env ( dev : String ) -> Result < Environment , Error > {
213
362
let mount_media =
0 commit comments