@@ -54,6 +54,29 @@ pub fn subcommands() -> Command {
54
54
. required ( false )
55
55
. value_parser ( PoolType :: types ( ) . to_vec ( ) )
56
56
. default_value ( PoolType :: Lvs . as_ref ( ) ) ,
57
+ )
58
+ . arg (
59
+ Arg :: new ( "cipher" )
60
+ . short ( 'c' )
61
+ . long ( "cipher" )
62
+ . help ( "The cipher to use for encryption" )
63
+ . required ( false )
64
+ . requires ( "encryption-key" ) ,
65
+ )
66
+ . arg (
67
+ Arg :: new ( "encryption-key" )
68
+ . short ( 'k' )
69
+ . long ( "encryption-key" )
70
+ . help ( "The encryption key of the pool in hexlified format" )
71
+ . required ( false ) ,
72
+ )
73
+ . arg (
74
+ Arg :: new ( "xts-key" )
75
+ . short ( 'e' )
76
+ . long ( "xts-key" )
77
+ . help ( "encryption key2 required for AES_XTS" )
78
+ . required ( false )
79
+ . required_if_eq ( "cipher" , "AES_XTS" ) ,
57
80
) ;
58
81
59
82
let import = Command :: new ( "import" )
@@ -86,6 +109,28 @@ pub fn subcommands() -> Command {
86
109
. required ( false )
87
110
. value_parser ( PoolType :: types ( ) . to_vec ( ) )
88
111
. default_value ( PoolType :: Lvs . as_ref ( ) ) ,
112
+ )
113
+ . arg (
114
+ Arg :: new ( "cipher" )
115
+ . short ( 'c' )
116
+ . long ( "cipher" )
117
+ . help ( "The cipher to use for encryption" )
118
+ . required ( false )
119
+ . requires ( "encryption-key" ) ,
120
+ )
121
+ . arg (
122
+ Arg :: new ( "encryption-key" )
123
+ . short ( 'k' )
124
+ . long ( "encryption-key" )
125
+ . help ( "The encryption key of the pool in hexlified format" )
126
+ . required ( false ) ,
127
+ )
128
+ . arg (
129
+ Arg :: new ( "xts-key" )
130
+ . short ( 'e' )
131
+ . long ( "xts-key" )
132
+ . help ( "encryption key2 required for AES_XTS" )
133
+ . required_if_eq ( "cipher" , "AES_XTS" ) ,
89
134
) ;
90
135
91
136
let destroy = Command :: new ( "destroy" )
@@ -211,6 +256,19 @@ async fn create(mut ctx: Context, matches: &ArgMatches) -> crate::Result<()> {
211
256
. to_owned ( ) ;
212
257
213
258
let uuid = matches. get_one :: < String > ( "uuid" ) ;
259
+ let cipher = matches. get_one :: < String > ( "cipher" ) ;
260
+
261
+ if let Some ( c) = cipher {
262
+ if !c. eq_ignore_ascii_case ( "AES_XTS" ) && !c. eq_ignore_ascii_case ( "AES_CBC" ) {
263
+ return Err ( Status :: invalid_argument (
264
+ "Need valid cipher(AES_XTS or AES_CBC)" ,
265
+ ) )
266
+ . context ( GrpcStatus ) ;
267
+ }
268
+ }
269
+
270
+ let enc_key = matches. get_one :: < String > ( "encryption-key" ) ;
271
+ let xts_key = matches. get_one :: < String > ( "xts-key" ) ;
214
272
215
273
let disks_list = matches
216
274
. get_many :: < String > ( "disk" )
@@ -251,6 +309,23 @@ async fn create(mut ctx: Context, matches: &ArgMatches) -> crate::Result<()> {
251
309
None => None ,
252
310
} ;
253
311
312
+ let enc_key_msg = enc_key. map ( |k| v1rpc:: common:: EncryptionKey {
313
+ key_name : "key_" . to_owned ( ) + k. as_str ( ) ,
314
+ key : k. clone ( ) . into ( ) ,
315
+ key_length : ( k. len ( ) * 4 ) as u32 ,
316
+ key2 : xts_key. map ( |k2| k2. clone ( ) . into ( ) ) ,
317
+ key2_length : xts_key. map ( |x| { x. len ( ) * 4 } as u32 ) ,
318
+ } ) ;
319
+
320
+ let enc_msg = enc_key_msg. map ( |e| {
321
+ v1rpc:: common:: create_pool_request:: Encryption :: Data ( v1rpc:: common:: EncryptionData {
322
+ cipher : v1rpc:: common:: Cipher :: from_str_name ( cipher. unwrap ( ) )
323
+ . unwrap ( )
324
+ . into ( ) ,
325
+ key : Some ( e) ,
326
+ } )
327
+ } ) ;
328
+
254
329
let response = ctx
255
330
. v1
256
331
. pool
@@ -261,7 +336,7 @@ async fn create(mut ctx: Context, matches: &ArgMatches) -> crate::Result<()> {
261
336
pooltype : v1rpc:: pool:: PoolType :: from ( pooltype) as i32 ,
262
337
cluster_size,
263
338
md_args : Some ( v1rpc:: pool:: PoolMetadataArgs { md_resv_ratio } ) ,
264
- encryption : None ,
339
+ encryption : enc_msg ,
265
340
} )
266
341
. await
267
342
. context ( GrpcStatus ) ?;
@@ -284,6 +359,21 @@ async fn create(mut ctx: Context, matches: &ArgMatches) -> crate::Result<()> {
284
359
Ok ( ( ) )
285
360
}
286
361
362
+ #[ derive( EnumString , VariantNames , AsRefStr ) ]
363
+ #[ strum( serialize_all = "UPPERCASE" ) ]
364
+ pub ( super ) enum Cipher {
365
+ AesCbc ,
366
+ AesXts ,
367
+ }
368
+ impl From < Cipher > for v1rpc:: common:: Cipher {
369
+ fn from ( value : Cipher ) -> Self {
370
+ match value {
371
+ Cipher :: AesCbc => Self :: AesCbc ,
372
+ Cipher :: AesXts => Self :: AesXts ,
373
+ }
374
+ }
375
+ }
376
+
287
377
#[ derive( EnumString , VariantNames , AsRefStr ) ]
288
378
#[ strum( serialize_all = "camelCase" ) ]
289
379
pub ( super ) enum PoolType {
@@ -312,6 +402,20 @@ async fn import(mut ctx: Context, matches: &ArgMatches) -> crate::Result<()> {
312
402
} ) ?
313
403
. to_owned ( ) ;
314
404
let uuid = matches. get_one :: < String > ( "uuid" ) ;
405
+ let cipher = matches. get_one :: < String > ( "cipher" ) ;
406
+
407
+ if let Some ( c) = cipher {
408
+ if !c. eq_ignore_ascii_case ( "AES_XTS" ) && !c. eq_ignore_ascii_case ( "AES_CBC" ) {
409
+ return Err ( Status :: invalid_argument (
410
+ "Need valid cipher(AES_XTS or AES_CBC)" ,
411
+ ) )
412
+ . context ( GrpcStatus ) ;
413
+ }
414
+ }
415
+
416
+ let enc_key = matches. get_one :: < String > ( "encryption-key" ) ;
417
+ let xts_key = matches. get_one :: < String > ( "xts-key" ) ;
418
+
315
419
let disks_list = matches
316
420
. get_many :: < String > ( "disk" )
317
421
. ok_or_else ( || ClientError :: MissingValue {
@@ -326,6 +430,23 @@ async fn import(mut ctx: Context, matches: &ArgMatches) -> crate::Result<()> {
326
430
. map_err ( |e| Status :: invalid_argument ( e. to_string ( ) ) )
327
431
. context ( GrpcStatus ) ?;
328
432
433
+ let enc_key_msg = enc_key. map ( |k| v1rpc:: common:: EncryptionKey {
434
+ key_name : "key_" . to_owned ( ) + k,
435
+ key : k. clone ( ) . into ( ) ,
436
+ key_length : k. len ( ) as u32 ,
437
+ key2 : xts_key. map ( |k2| k2. clone ( ) . into ( ) ) ,
438
+ key2_length : xts_key. map ( |x| x. len ( ) as u32 ) ,
439
+ } ) ;
440
+
441
+ let enc_msg = enc_key_msg. map ( |e| {
442
+ v1rpc:: common:: import_pool_request:: Encryption :: Data ( v1rpc:: common:: EncryptionData {
443
+ cipher : v1rpc:: common:: Cipher :: from_str_name ( cipher. unwrap ( ) )
444
+ . unwrap ( )
445
+ . into ( ) ,
446
+ key : Some ( e) ,
447
+ } )
448
+ } ) ;
449
+
329
450
let response = ctx
330
451
. v1
331
452
. pool
@@ -334,7 +455,7 @@ async fn import(mut ctx: Context, matches: &ArgMatches) -> crate::Result<()> {
334
455
uuid : uuid. map ( ToString :: to_string) ,
335
456
disks : disks_list,
336
457
pooltype : v1rpc:: pool:: PoolType :: from ( pooltype) as i32 ,
337
- encryption : None ,
458
+ encryption : enc_msg ,
338
459
} )
339
460
. await
340
461
. context ( GrpcStatus ) ?;
0 commit comments