LCOV - code coverage report
Current view: top level - pkg/storaged/stratis - create-dialog.jsx Coverage Total Hit
Test: cockpit Lines: 86.1 % 158 136
Test Date: 2026-07-13 10:00:01

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2023 Red Hat, Inc.
       3              :  * SPDX-License-Identifier: LGPL-2.1-or-later
       4              :  */
       5              : 
       6          113 : import cockpit from "cockpit";
       7              : import client from "../client.js";
       8              : 
       9              : import { dialog_open, TextInput, CheckBoxes, PassInput, SelectSpaces } from "../dialog.jsx";
      10              : import { decode_filename, get_available_spaces, prepare_available_spaces } from "../utils.js";
      11              : 
      12              : import { validate_pool_name, std_reply, get_unused_keydesc, with_stored_passphrase, confirm_tang_trust } from "./utils.jsx";
      13              : import { validate_url, get_tang_adv } from "../crypto/tang.jsx";
      14              : 
      15          113 : const _ = cockpit.gettext;
      16              : 
      17            8 : function manager_create_pool(name, devs, key_desc, clevis_info) {
      18              :     // "clevis_info" is either falsy or an array with two elements:
      19              :     //
      20              :     //   [ pin, pin_config ]
      21              :     //
      22              :     // This array can be used directly with the (b(ss)) signature of
      23              :     // the r6 CreatePool call, but needs to be taken apart for the
      24              :     // a((bu)ss) signature of the r8 CreatePool call.
      25              : 
      26            0 :     if (client.stratis_interface_revision < 8) {
      27            0 :         let key_desc_arg = [false, ""];
      28            0 :         if (key_desc)
      29            0 :             key_desc_arg = [true, key_desc];
      30            0 :         let clevis_info_arg = [false, ["", ""]];
      31            0 :         if (clevis_info)
      32            0 :             clevis_info_arg = [true, clevis_info];
      33            0 :         return client.stratis_manager.CreatePool(name,
      34            0 :                                                  devs,
      35            0 :                                                  key_desc_arg,
      36            0 :                                                  clevis_info_arg);
      37            0 :     } else {
      38            8 :         const any_slot = [false, 0];
      39            8 :         const key_descs_arg = [];
      40            8 :         if (key_desc)
      41            1 :             key_descs_arg.push([any_slot, key_desc]);
      42            8 :         const clevis_infos_arg = [];
      43            8 :         if (clevis_info)
      44            0 :             clevis_infos_arg.push([any_slot, clevis_info[0], clevis_info[1]]);
      45            8 :         return client.stratis_manager.CreatePool(name,
      46            8 :                                                  devs,
      47            8 :                                                  key_descs_arg,
      48            8 :                                                  clevis_infos_arg,
      49            8 :                                                  [false, 0], // journal_size
      50            8 :                                                  [false, ""], // tag_spec
      51            8 :                                                  [false, false]); // allocate_superblock
      52            8 :     }
      53            8 : }
      54              : 
      55            9 : export function create_stratis_pool() {
      56            9 :     function find_pool(name) {
      57            2 :         for (const p in client.stratis_pools) {
      58            2 :             if (client.stratis_pools[p].Name == name)
      59            2 :                 return client.stratis_pools[p];
      60            2 :         }
      61            9 :         return null;
      62            9 :     }
      63              : 
      64            9 :     let name;
      65            9 :     for (let i = 0; i < 1000; i++) {
      66            9 :         name = "pool" + i.toFixed();
      67            9 :         if (!find_pool(name))
      68            9 :             break;
      69            9 :     }
      70              : 
      71            9 :     dialog_open({
      72            9 :         Title: _("Create Stratis pool"),
      73            9 :         Fields: [
      74            9 :             TextInput("name", _("Name"),
      75            9 :                       {
      76            9 :                           value: name,
      77            8 :                           validate: name => validate_pool_name(null, name)
      78            9 :                       }),
      79            9 :             SelectSpaces("disks", _("Block devices"),
      80            9 :                          {
      81            9 :                              empty_warning: _("No block devices are available."),
      82            8 :                              validate: function (disks) {
      83            8 :                                  if (disks.length === 0)
      84            0 :                                      return _("At least one block device is needed.");
      85            8 :                              },
      86            9 :                              spaces: get_available_spaces()
      87            9 :                          }),
      88            9 :             CheckBoxes("encrypt_pass", _("Options"),
      89            9 :                        {
      90            9 :                            fields: [
      91            9 :                                {
      92            9 :                                    tag: "on",
      93            9 :                                    title: _("Encrypt data with a passphrase"),
      94            9 :                                }
      95            9 :                            ],
      96            9 :                            nested_fields: [
      97            9 :                                PassInput("passphrase", _("Passphrase"),
      98            9 :                                          {
      99            1 :                                              validate: function (phrase) {
     100            1 :                                                  if (phrase === "")
     101            0 :                                                      return _("Passphrase cannot be empty");
     102            1 :                                              },
     103            9 :                                              visible: vals => vals.encrypt_pass.on,
     104            9 :                                              new_password: true
     105            9 :                                          }),
     106            9 :                                PassInput("passphrase2", _("Confirm"),
     107            9 :                                          {
     108            1 :                                              validate: function (phrase2, vals) {
     109            1 :                                                  if (phrase2 != vals.passphrase)
     110            0 :                                                      return _("Passphrases do not match");
     111            1 :                                              },
     112            9 :                                              visible: vals => vals.encrypt_pass.on,
     113            9 :                                              new_password: true
     114            9 :                                          })
     115            9 :                            ]
     116            9 :                        }),
     117            9 :             CheckBoxes("encrypt_tang", "",
     118            9 :                        {
     119            9 :                            fields: [
     120            9 :                                { tag: "on", title: _("Encrypt data with a Tang keyserver") }
     121            9 :                            ],
     122            9 :                            nested_fields: [
     123            9 :                                TextInput("tang_url", _("Keyserver address"),
     124            9 :                                          {
     125            9 :                                              validate: validate_url,
     126            9 :                                              visible: vals => vals.encrypt_tang && vals.encrypt_tang.on
     127            9 :                                          }),
     128            9 :                            ]
     129            9 :                        }),
     130            9 :             CheckBoxes("overprov", "",
     131            9 :                        {
     132            9 :                            value: { on: true },
     133            9 :                            fields: [
     134            9 :                                {
     135            9 :                                    tag: "on",
     136            9 :                                    title: _("Overprovisioning"),
     137            9 :                                }
     138            9 :                            ]
     139            9 :                        })
     140            9 :         ],
     141            9 :         Action: {
     142            9 :             Title: _("Create"),
     143            8 :             action: function (vals) {
     144            8 :                 return prepare_available_spaces(client, vals.disks).then(function (paths) {
     145            8 :                     const devs = paths.map(p => decode_filename(client.blocks[p].PreferredDevice));
     146              : 
     147            8 :                     function create(key_desc, adv) {
     148            8 :                         let clevis_info = null;
     149            8 :                         if (adv)
     150            0 :                             clevis_info = ["tang", JSON.stringify({ url: vals.tang_url, adv })];
     151            8 :                         return manager_create_pool(vals.name, devs, key_desc, clevis_info)
     152            8 :                                 .then(std_reply)
     153            8 :                                 .then(result => {
     154            1 :                                     if (vals.overprov && !vals.overprov.on && result[0]) {
     155            1 :                                         const path = result[1][0];
     156            1 :                                         return client.wait_for(() => client.stratis_pools[path])
     157            1 :                                                 .then(pool => {
     158            1 :                                                     return client.stratis_set_property(pool,
     159            1 :                                                                                        "Overprovisioning",
     160            1 :                                                                                        "b", false);
     161            1 :                                                 });
     162            1 :                                     }
     163            8 :                                 });
     164            8 :                     }
     165              : 
     166            8 :                     function create2(adv) {
     167            1 :                         if (vals.encrypt_pass.on) {
     168            1 :                             return get_unused_keydesc(client, vals.name)
     169            1 :                                     .then(keydesc => with_stored_passphrase(client, keydesc, vals.passphrase,
     170            1 :                                                                             () => create(keydesc, adv)));
     171            0 :                         } else {
     172            7 :                             return create(false, adv);
     173            7 :                         }
     174            8 :                     }
     175              : 
     176            0 :                     if (vals.encrypt_tang && vals.encrypt_tang.on) {
     177            0 :                         return get_tang_adv(vals.tang_url)
     178            0 :                                 .then(adv => confirm_tang_trust(vals.tang_url, adv, () => create2(adv)));
     179            0 :                     } else {
     180            8 :                         return create2(false);
     181            8 :                     }
     182            8 :                 });
     183            8 :             }
     184            9 :         }
     185            9 :     });
     186            9 : }
        

Generated by: LCOV version 2.0-1