LCOV - code coverage report
Current view: top level - pkg/storaged/stratis - utils.jsx Coverage Total Hit
Test: cockpit Lines: 88.8 % 116 103
Test Date: 2026-06-25 11:17:56

            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          113 : import React from "react";
       8              : import client from "../client";
       9              : 
      10              : import { for_each_async, reload_systemd, encode_filename } from "../utils.js";
      11              : import { dialog_open } from "../dialog.jsx";
      12              : import { TangKeyVerification } from "../crypto/tang.jsx";
      13              : 
      14          113 : const _ = cockpit.gettext;
      15              : 
      16            9 : export function validate_pool_name(pool, name) {
      17            9 :     if (name == "")
      18            0 :         return _("Name can not be empty.");
      19            2 :     if ((!pool || name != pool.Name) && client.stratis_poolnames_pool[name])
      20            0 :         return _("A pool with this name exists already.");
      21            9 : }
      22              : 
      23           13 : export function std_reply(result, code, message) {
      24           13 :     if (code)
      25            0 :         return Promise.reject(message);
      26              :     else
      27           12 :         return Promise.resolve(result);
      28           13 : }
      29              : 
      30              : export function with_keydesc(client, pool, func) {
      31              :     if (!pool.KeyDescription ||
      32              :         !pool.KeyDescription[0] ||
      33              :         !pool.KeyDescription[1][0]) {
      34              :         return func(false);
      35              :     } else {
      36              :         const keydesc = pool.KeyDescription[1][1];
      37              :         return client.stratis_manager.ListKeys()
      38              :                 .catch(() => []) // not-covered: internal error
      39              :                 .then(keys => func(keydesc, keys.indexOf(keydesc) >= 0));
      40              :     }
      41              : }
      42              : 
      43            1 : export function with_stored_passphrase(client, keydesc, passphrase, func) {
      44            1 :     return client.stratis_store_passphrase(keydesc, passphrase)
      45            1 :             .then(func)
      46            1 :             .finally(() => {
      47            1 :                 return client.stratis_manager.UnsetKey(keydesc)
      48            1 :                         .then(std_reply)
      49            0 :                         .catch(ex => { console.warn("Failed to remove passphrase from key ring", ex.toString()) }); // not-covered: internal error
      50            1 :             });
      51            1 : }
      52              : 
      53            1 : export function get_unused_keydesc(client, desc_prefix) {
      54            1 :     return client.stratis_manager.ListKeys()
      55            0 :             .catch(() => []) // not-covered: internal error
      56            1 :             .then(keys => {
      57            1 :                 let desc;
      58            1 :                 for (let i = 0; i < 1000; i++) {
      59            0 :                     desc = desc_prefix + (i > 0 ? "." + i.toFixed() : "");
      60            1 :                     if (keys.indexOf(desc) == -1)
      61            1 :                         break;
      62            1 :                 }
      63            1 :                 return desc;
      64            1 :             });
      65            1 : }
      66              : 
      67            1 : export function confirm_tang_trust(url, adv, action) {
      68            1 :     dialog_open({
      69            1 :         Title: _("Verify key"),
      70            1 :         Body: <TangKeyVerification url={url} adv={adv} />,
      71            1 :         Action: {
      72            1 :             Title: _("Trust key"),
      73            1 :             action
      74            1 :         }
      75            1 :     });
      76            1 : }
      77              : 
      78              : export function check_stratis_warnings(client, enter_warning) {
      79              :     for (const p in client.stratis_pools) {
      80              :         const blockdevs = client.stratis_pool_blockdevs[p] || [];
      81              :         const pool = client.stratis_pools[p];
      82              :         if (blockdevs.some(bd => bd.NewPhysicalSize[0] && Number(bd.NewPhysicalSize[1]) > Number(bd.TotalPhysicalSize)))
      83              :             enter_warning(p, { warning: "unused-blockdevs" });
      84              :         if (pool.AvailableActions && pool.AvailableActions !== "fully_operational")
      85              :             enter_warning(p, { warning: "not-fully-operational" });
      86              :     }
      87              : }
      88              : 
      89            6 : function teardown_block(block) {
      90            4 :     return for_each_async(block.Configuration, c => block.RemoveConfigurationItem(c, {}));
      91            6 : }
      92              : 
      93            6 : export function destroy_filesystem(fsys) {
      94            6 :     const block = client.slashdevs_block[fsys.Devnode];
      95            6 :     const pool = client.stratis_pools[fsys.Pool];
      96              : 
      97            6 :     return teardown_block(block).then(() => pool.DestroyFilesystems([fsys.path]).then(std_reply));
      98            6 : }
      99              : 
     100            9 : export function validate_fs_name(fsys, name, filesystems) {
     101            9 :     if (name == "")
     102            0 :         return _("Name can not be empty.");
     103            2 :     if (!fsys || name != fsys.Name) {
     104            4 :         for (const fs of filesystems) {
     105            4 :             if (fs.Name == name)
     106            0 :                 return _("A filesystem with this name exists already in this pool.");
     107            4 :         }
     108            9 :     }
     109            9 : }
     110              : 
     111            8 : export function set_mount_options(path, vals, forced_options) {
     112            8 :     let mount_options = [];
     113              : 
     114            3 :     if (vals.variant == "nomount" || vals.at_boot == "never")
     115            8 :         mount_options.push("noauto");
     116            7 :     if (vals.mount_options?.ro)
     117            0 :         mount_options.push("ro");
     118            8 :     if (vals.at_boot == "never")
     119            3 :         mount_options.push("x-cockpit-never-auto");
     120            8 :     if (vals.at_boot == "nofail")
     121            7 :         mount_options.push("nofail");
     122            8 :     if (vals.at_boot == "netdev")
     123            1 :         mount_options.push("_netdev");
     124            7 :     if (vals.mount_options?.extra)
     125            0 :         mount_options.push(vals.mount_options.extra);
     126              : 
     127            8 :     mount_options = mount_options.concat(forced_options);
     128              : 
     129            8 :     let mount_point = vals.mount_point;
     130            8 :     if (mount_point == "")
     131            6 :         return Promise.resolve();
     132            4 :     if (mount_point[0] != "/")
     133            0 :         mount_point = "/" + mount_point;
     134            4 :     mount_point = client.add_mount_point_prefix(mount_point);
     135              : 
     136            4 :     const config =
     137            4 :           ["fstab",
     138            4 :               {
     139            4 :                   dir: { t: 'ay', v: encode_filename(mount_point) },
     140            4 :                   type: { t: 'ay', v: encode_filename("auto") },
     141            0 :                   opts: { t: 'ay', v: encode_filename(mount_options.join(",") || "defaults") },
     142            8 :                   freq: { t: 'i', v: 0 },
     143            8 :                   passno: { t: 'i', v: 0 },
     144            8 :               }
     145            8 :           ];
     146              : 
     147            4 :     function udisks_block_for_stratis_fsys() {
     148            4 :         const fsys = client.stratis_filesystems[path];
     149            4 :         return fsys && client.slashdevs_block[fsys.Devnode];
     150            4 :     }
     151              : 
     152            8 :     return client.wait_for(udisks_block_for_stratis_fsys)
     153            4 :             .then(block => {
     154              :             // HACK - need a explicit "change" event
     155            4 :                 return block.Rescan({})
     156            4 :                         .then(() => {
     157            4 :                             return client.wait_for(() => client.blocks_fsys[block.path])
     158            4 :                                     .then(fsys => {
     159            4 :                                         return block.AddConfigurationItem(config, {})
     160            4 :                                                 .then(reload_systemd)
     161            4 :                                                 .then(() => {
     162            4 :                                                     if (vals.variant != "nomount")
     163            0 :                                                         return client.mount_at(block, mount_point);
     164              :                                                     else
     165            1 :                                                         return Promise.resolve();
     166            4 :                                                 });
     167            4 :                                     });
     168            4 :                         });
     169            4 :             });
     170            8 : }
        

Generated by: LCOV version 2.0-1