Rewrite upgrade-simple to C++

This commit is contained in:
Vitaliy Filippov
2022-08-18 01:31:31 +03:00
parent a16263e88c
commit 40d8d65188
10 changed files with 217 additions and 147 deletions
+1 -1
View File
@@ -195,7 +195,7 @@ configure_file(vitastor.pc.in vitastor.pc @ONLY)
# vitastor-disk
add_executable(vitastor-disk
disk_tool.cpp disk_simple_offsets.cpp
disk_tool_journal.cpp disk_tool_meta.cpp disk_tool_prepare.cpp disk_tool_resize.cpp disk_tool_udev.cpp disk_tool_utils.cpp
disk_tool_journal.cpp disk_tool_meta.cpp disk_tool_prepare.cpp disk_tool_resize.cpp disk_tool_udev.cpp disk_tool_utils.cpp disk_tool_upgrade.cpp
crc32c.c str_util.cpp ../json11/json11.cpp rw_blocking.cpp allocator.cpp ringloop.cpp blockstore_disk.cpp
)
target_link_libraries(vitastor-disk
+26
View File
@@ -18,6 +18,7 @@ static const char *help_text =
" In the second form, you omit <devices> and pass --data_device, --journal_device\n"
" and/or --meta_device which must be already existing partitions. In this case\n"
" a single OSD is created.\n"
" Requires `vitastor-cli`, `blkid` and `sfdisk` utilities.\n"
" OPTIONS may include:\n"
" --hybrid\n"
" Prepare hybrid (HDD+SSD) OSDs using provided devices. SSDs will be used for\n"
@@ -45,6 +46,13 @@ static const char *help_text =
" Use disks for OSD data even if they already have non-Vitastor partitions,\n"
" but only if these take up no more than this percent of disk space.\n"
"\n"
"vitastor-disk upgrade-simple <UNIT_FILE|OSD_NUMBER>\n"
" Upgrade an OSD created by old (0.7.1 and older) make-osd.sh or make-osd-hybrid.js scripts.\n"
" Adds superblocks to OSD devices, disables old vitastor-osdN unit and replaces it with vitastor-osd@N.\n"
" UNIT_FILE must be /etc/systemd/system/vitastor-osd<OSD_NUMBER>.service.\n"
" Note that the procedure isn't atomic and may ruin OSD data if an error happens.\n"
" Requires the `sfdisk` utility.\n"
"\n"
"vitastor-disk resize <ALL_OSD_PARAMETERS> <NEW_LAYOUT> [--iodepth 32]\n"
" Resize data area and/or rewrite/move journal and metadata\n"
" ALL_OSD_PARAMETERS must include all (at least all disk-related)\n"
@@ -263,6 +271,24 @@ int main(int argc, char *argv[])
}
return self.pre_exec_osd(cmd[1]);
}
else if (!strcmp(cmd[0], "prepare"))
{
std::vector<std::string> devs;
for (int i = 1; i < cmd.size(); i++)
{
devs.push_back(cmd[i]);
}
return self.prepare(devs);
}
else if (!strcmp(cmd[0], "upgrade-simple"))
{
if (cmd.size() != 2)
{
fprintf(stderr, "Exactly 1 OSD number or systemd unit path is required\n");
return 1;
}
return self.upgrade_simple_unit(cmd[1]);
}
else
{
print_help(help_text, "vitastor-disk", cmd.size() > 1 ? cmd[1] : "", self.all);
+2
View File
@@ -120,6 +120,8 @@ struct disk_tool_t
json11::Json add_partitions(vitastor_dev_info_t & devinfo, std::vector<std::string> sizes);
std::vector<std::string> get_new_data_parts(vitastor_dev_info_t & dev, uint64_t osd_per_disk, uint64_t max_other_percent);
int get_meta_partition(std::vector<vitastor_dev_info_t> & ssds, std::map<std::string, std::string> & options);
int upgrade_simple_unit(std::string unit);
};
void disk_tool_simple_offsets(json11::Json cfg, bool json_output);
+1 -1
View File
@@ -255,7 +255,7 @@ json11::Json disk_tool_t::add_partitions(vitastor_dev_info_t & devinfo, std::vec
{
script += "+ "+size+" "+std::string(VITASTOR_PART_TYPE)+"\n";
}
if (shell_exec({ "/sbin/sfdisk", devinfo.path }, script, NULL, NULL) != 0)
if (shell_exec({ "/sbin/sfdisk", "--force", devinfo.path }, script, NULL, NULL) != 0)
{
fprintf(stderr, "Failed to add %lu partition(s) with sfdisk\n", sizes.size());
return {};
+6
View File
@@ -1,6 +1,7 @@
// Copyright (c) Vitaliy Filippov, 2019+
// License: VNPL-1.1 (see README.md for details)
#include <sys/file.h>
#include <dirent.h>
#include "disk_tool.h"
@@ -109,6 +110,11 @@ uint32_t disk_tool_t::write_osd_superblock(std::string device, json11::Json para
free(buf);
return 0;
}
// Lock the file
if (flock(fd, LOCK_EX|LOCK_NB) < 0)
{
fprintf(stderr, "Warning: Failed to lock %s with flock - udev autodetection may fail. Error: %s\n", device.c_str(), strerror(errno));
}
int r = write_blocking(fd, buf, buf_len);
if (r < 0)
{
+178
View File
@@ -0,0 +1,178 @@
// Copyright (c) Vitaliy Filippov, 2019+
// License: VNPL-1.1 (see README.md for details)
#include <regex>
#include "disk_tool.h"
#include "str_util.h"
static std::map<std::string, std::string> read_vitastor_unit(std::string unit)
{
std::smatch m;
if (unit == "" || !std::regex_match(unit, m, std::regex(".*/vitastor-osd\\d+\\.service")))
{
fprintf(stderr, "unit file name does not match <path>/vitastor-osd<NUMBER>.service\n");
return {};
}
std::string text = read_file(unit);
if (!std::regex_search(text, m, std::regex("\nExecStart\\s*=[^\n]+vitastor-osd\\s*(([^\\\\\n&>\\d]+|\\\\[ \t\r]*\n|\\d[^>])+)")))
{
fprintf(stderr, "Failed to extract ExecStart command from %s\n", unit.c_str());
return {};
}
std::string cmd = trim(m[1]);
cmd = str_replace(cmd, "\\\n", " ");
std::string key;
std::map<std::string, std::string> r;
auto ns = std::regex("\\S+");
for (auto it = std::sregex_token_iterator(cmd.begin(), cmd.end(), ns, 0), end = std::sregex_token_iterator();
it != end; it++)
{
if (key == "" && ((std::string)(*it)).substr(0, 2) == "--")
key = ((std::string)(*it)).substr(2);
else if (key != "")
{
r[key] = *it;
key = "";
}
}
return r;
}
static int fix_partition_type(std::string dev_by_uuid)
{
auto uuid = strtolower(dev_by_uuid.substr(dev_by_uuid.rfind('/')+1));
std::string parent_dev = get_parent_device(realpath_str(dev_by_uuid, false));
if (parent_dev == "")
return 1;
auto pt = read_parttable("/dev/"+parent_dev);
if (pt.is_null())
return 1;
std::string script = "label: gpt\n\n";
for (const auto & part: pt["partitions"].array_items())
{
bool this_part = (strtolower(part["uuid"].string_value()) == uuid);
if (this_part && strtolower(part["type"].string_value()) == "e7009fac-a5a1-4d72-af72-53de13059903")
{
// Already correct type
return 0;
}
script += part["node"].string_value()+": ";
bool first = true;
for (const auto & kv: part.object_items())
{
if (kv.first != "node")
{
script += (first ? "" : ", ")+kv.first+"="+
(kv.first == "type" && this_part
? "e7009fac-a5a1-4d72-af72-53de13059903"
: (kv.second.is_string() ? kv.second.string_value() : kv.second.dump()));
first = false;
}
}
script += "\n";
}
return shell_exec({ "/sbin/sfdisk", "--no-reread", "--force", "/dev/"+parent_dev }, script, NULL, NULL);
}
int disk_tool_t::upgrade_simple_unit(std::string unit)
{
if (stoull_full(unit) != 0)
{
// OSD number
unit = "/etc/systemd/system/vitastor-osd"+unit+".service";
}
auto options = read_vitastor_unit(unit);
if (!options.size())
return 1;
if (!stoull_full(options["osd_num"], 10) || options["data_device"] == "")
{
fprintf(stderr, "osd_num or data_device are missing in %s\n", unit.c_str());
return 1;
}
if (options["data_device"].substr(0, 22) != "/dev/disk/by-partuuid/" ||
options["meta_device"] != "" && options["meta_device"].substr(0, 22) != "/dev/disk/by-partuuid/" ||
options["journal_device"] != "" && options["journal_device"].substr(0, 22) != "/dev/disk/by-partuuid/")
{
fprintf(
stderr, "data_device, meta_device and journal_device must begin with"
" /dev/disk/by-partuuid/ i.e. they must be GPT partitions identified by UUIDs"
);
return 1;
}
// Stop and disable the service
auto service_name = unit.substr(unit.rfind('/') + 1);
if (shell_exec({ "systemctl", "disable", "--now", service_name }, "", NULL, NULL) != 0)
{
return 1;
}
uint64_t j_o = stoull_full(options["journal_offset"]);
uint64_t m_o = stoull_full(options["meta_offset"]);
uint64_t d_o = stoull_full(options["data_offset"]);
bool m_is_d = options["meta_device"] == "" || options["meta_device"] == options["data_device"];
bool j_is_m = options["journal_device"] == "" || options["journal_device"] == options["meta_device"];
bool j_is_d = j_is_m && m_is_d || options["journal_device"] == options["data_device"];
if (d_o < 4096 || j_o < 4096 || m_o < 4096)
{
// Resize data
uint64_t blk = stoull_full(options["block_size"]);
blk = blk ? blk : 128*1024;
std::map<std::string, uint64_t> resize;
if (d_o < 4096 || m_is_d && m_o < 4096 && m_o < d_o || j_is_d && j_o < 4096 && j_o < d_o)
{
resize["new_data_offset"] = d_o+blk;
if (m_is_d && m_o < d_o)
resize["new_meta_offset"] = m_o+blk;
if (j_is_d && j_o < d_o)
resize["new_journal_offset"] = j_o+blk;
}
if (!m_is_d && m_o < 4096)
{
resize["new_meta_offset"] = m_o+4096;
if (j_is_m && m_o < j_o)
resize["new_journal_offset"] = j_o+4096;
}
if (!j_is_d && !j_is_m && j_o < 4096)
resize["new_journal_offset"] = j_o+4096;
disk_tool_t resizer;
resizer.options = options;
for (auto & kv: resize)
resizer.options[kv.first] = std::to_string(kv.second);
if (resizer.resize_data() != 0)
{
// FIXME: Resize with backup or journal
fprintf(
stderr, "Failed to resize data to make space for the superblock\n"
"Sorry, but your OSD may now be corrupted depending on what went wrong during resize :-(\n"
"Please review the messages above and take action accordingly\n"
);
return 1;
}
for (auto & kv: resize)
options[kv.first.substr(4)] = std::to_string(kv.second);
}
// Write superblocks
if (!write_osd_superblock(options["data_device"], options) ||
(!m_is_d && !write_osd_superblock(options["meta_device"], options)) ||
(!j_is_m && !j_is_d && !write_osd_superblock(options["journal_device"], options)))
{
return 1;
}
// Change partition types
if (fix_partition_type(options["data_device"]) != 0 ||
(!m_is_d && fix_partition_type(options["meta_device"]) != 0) ||
(!j_is_m && !j_is_d && fix_partition_type(options["journal_device"]) != 0))
{
return 1;
}
// Enable the new unit
if (shell_exec({ "systemctl", "enable", "--now", "vitastor-osd@"+options["osd_num"] }, "", NULL, NULL) != 0)
{
fprintf(stderr, "Failed to enable systemd unit vitastor-osd@%s\n", options["osd_num"].c_str());
return 1;
}
fprintf(
stderr, "\nOK: Converted OSD %s to the new scheme. The new service name is vitastor-osd@%s\n",
options["osd_num"].c_str(), options["osd_num"].c_str()
);
return 0;
}
+1 -2
View File
@@ -148,13 +148,12 @@ int shell_exec(const std::vector<std::string> & cmd, const std::string & in, std
close(child_stdout[1]);
close(child_stderr[0]);
close(child_stderr[1]);
//char *argv[] = { (char*)"/bin/sh", (char*)"-c", (char*)cmd.c_str(), NULL };
char *argv[cmd.size()+1];
for (int i = 0; i < cmd.size(); i++)
{
argv[i] = (char*)cmd[i].c_str();
}
argv[cmd.size()-1] = NULL;
argv[cmd.size()] = NULL;
execvp(argv[0], argv);
std::string full_cmd;
for (int i = 0; i < cmd.size(); i++)