/* * Copyright (C) 2023 Red Hat, Inc. * SPDX-License-Identifier: LGPL-2.1-or-later */ import cockpit from "cockpit"; import client from "../client.js"; import { dialog_open, TextInput, CheckBoxes, PassInput, SelectSpaces } from "../dialog.jsx"; import { decode_filename, get_available_spaces, prepare_available_spaces } from "../utils.js"; import { validate_pool_name, std_reply, get_unused_keydesc, with_stored_passphrase, confirm_tang_trust } from "./utils.jsx"; import { remember_passphrase } from "../anaconda.jsx"; import { validate_url, get_tang_adv } from "../crypto/tang.jsx"; const _ = cockpit.gettext; function manager_create_pool(name, devs, key_desc, clevis_info) { // "clevis_info" is either falsy or an array with two elements: // // [ pin, pin_config ] // // This array can be used directly with the (b(ss)) signature of // the r6 CreatePool call, but needs to be taken apart for the // a((bu)ss) signature of the r8 CreatePool call. if (client.stratis_interface_revision < 8) { let key_desc_arg = [false, ""]; if (key_desc) key_desc_arg = [true, key_desc]; let clevis_info_arg = [false, ["", ""]]; if (clevis_info) clevis_info_arg = [true, clevis_info]; return client.stratis_manager.CreatePool(name, devs, key_desc_arg, clevis_info_arg); } else { const any_slot = [false, 0]; const key_descs_arg = []; if (key_desc) key_descs_arg.push([any_slot, key_desc]); const clevis_infos_arg = []; if (clevis_info) clevis_infos_arg.push([any_slot, clevis_info[0], clevis_info[1]]); return client.stratis_manager.CreatePool(name, devs, key_descs_arg, clevis_infos_arg, [false, 0], // journal_size [false, ""], // tag_spec [false, false]); // allocate_superblock } } export function create_stratis_pool() { function find_pool(name) { for (const p in client.stratis_pools) { if (client.stratis_pools[p].Name === name) return client.stratis_pools[p]; } return null; } let name; for (let i = 0; i < 1000; i++) { name = "pool" + i.toFixed(); if (!find_pool(name)) break; } dialog_open({ Title: _("Create Stratis pool"), Fields: [ TextInput("name", _("Name"), { value: name, validate: name => validate_pool_name(null, name) }), SelectSpaces("disks", _("Block devices"), { empty_warning: _("No block devices are available."), validate: function (disks) { if (disks.length === 0) return _("At least one block device is needed."); }, spaces: get_available_spaces() }), CheckBoxes("encrypt_pass", _("Options"), { fields: [ { tag: "on", title: _("Encrypt data with a passphrase"), } ], nested_fields: [ PassInput("passphrase", _("Passphrase"), { validate: function (phrase) { if (phrase === "") return _("Passphrase cannot be empty"); }, visible: vals => vals.encrypt_pass.on, new_password: true }), PassInput("passphrase2", _("Confirm"), { validate: function (phrase2, vals) { if (phrase2 !== vals.passphrase) return _("Passphrases do not match"); }, visible: vals => vals.encrypt_pass.on, new_password: true }) ] }), CheckBoxes("encrypt_tang", "", { visible: () => !client.in_anaconda_mode(), fields: [ { tag: "on", title: _("Encrypt data with a Tang keyserver") } ], nested_fields: [ TextInput("tang_url", _("Keyserver address"), { validate: validate_url, visible: vals => vals.encrypt_tang && vals.encrypt_tang.on }), ] }), CheckBoxes("overprov", "", { value: { on: true }, fields: [ { tag: "on", title: _("Overprovisioning"), } ] }) ], Action: { Title: _("Create"), action: function (vals) { return prepare_available_spaces(client, vals.disks).then(function (paths) { const devs = paths.map(p => decode_filename(client.blocks[p].PreferredDevice)); function create(key_desc, adv) { let clevis_info = null; if (adv) clevis_info = ["tang", JSON.stringify({ url: vals.tang_url, adv })]; return manager_create_pool(vals.name, devs, key_desc, clevis_info) .then(std_reply) .then(result => { if (key_desc && vals.passphrase) { for (const p of paths) { const block = client.blocks[p]; if (block) remember_passphrase(block, vals.passphrase); } } if (vals.overprov && !vals.overprov.on && result[0]) { const path = result[1][0]; return client.wait_for(() => client.stratis_pools[path]) .then(pool => { return client.stratis_set_property(pool, "Overprovisioning", "b", false); }); } }); } function create2(adv) { if (vals.encrypt_pass.on) { return get_unused_keydesc(client, vals.name) .then(keydesc => with_stored_passphrase(client, keydesc, vals.passphrase, () => create(keydesc, adv))); } else { return create(false, adv); } } if (vals.encrypt_tang && vals.encrypt_tang.on) { return get_tang_adv(vals.tang_url) .then(adv => confirm_tang_trust(vals.tang_url, adv, () => create2(adv))); } else { return create2(false); } }); } } }); }