Skip to content

Commit

Permalink
Merge pull request #3705 from canonical/improve-cloud-init-errors
Browse files Browse the repository at this point in the history
Improve cloud-init error messages
  • Loading branch information
andrei-toterman authored Oct 10, 2024
2 parents 950779c + 144e09e commit 6dd1800
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 14 deletions.
29 changes: 17 additions & 12 deletions src/client/cli/cmd/launch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,36 +378,41 @@ mp::ParseCode cmd::Launch::parse_args(mp::ArgParser* parser)

if (parser->isSet(cloudInitOption))
{
constexpr auto err_msg_template = "Could not load cloud-init configuration: {}";
try
{
const QString& cloud_init_file = parser->value(cloudInitOption);
YAML::Node node;
const QString& cloudInitFile = parser->value(cloudInitOption);
if (cloudInitFile == "-")
if (cloud_init_file == "-")
{
node = YAML::Load(term->read_all_cin());
}
else if (cloudInitFile.startsWith("http://") || cloudInitFile.startsWith("https://"))
else if (cloud_init_file.startsWith("http://") || cloud_init_file.startsWith("https://"))
{
URLDownloader downloader{std::chrono::minutes{1}};
auto downloaded_yaml = downloader.download(QUrl(cloudInitFile));
auto downloaded_yaml = downloader.download(QUrl(cloud_init_file));
node = YAML::Load(downloaded_yaml.toStdString());
}
else
{
auto file_type = fs::status(cloudInitFile.toStdString()).type();
auto cloud_init_file_stdstr = cloud_init_file.toStdString();
auto file_type = fs::status(cloud_init_file_stdstr).type();
if (file_type != fs::file_type::regular && file_type != fs::file_type::fifo)
{
cerr << "error: No such file: " << cloudInitFile.toStdString() << "\n";
return ParseCode::CommandLineError;
}
throw YAML::BadFile{cloud_init_file_stdstr};

node = YAML::LoadFile(cloudInitFile.toStdString());
node = YAML::LoadFile(cloud_init_file_stdstr);
}
request.set_cloud_init_user_data(YAML::Dump(node));
}
catch (const std::exception& e)
catch (const YAML::BadFile& e)
{
auto err_detail = fmt::format("{}\n{}", e.what(), "Please ensure that Multipass can read it.");
fmt::println(cerr, err_msg_template, err_detail);
return ParseCode::CommandLineError;
}
catch (const YAML::Exception& e)
{
cerr << "error loading cloud-init config: " << e.what() << "\n";
fmt::println(cerr, err_msg_template, e.what());
return ParseCode::CommandLineError;
}
}
Expand Down
12 changes: 10 additions & 2 deletions tests/test_cli_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1097,17 +1097,25 @@ TEST_F(Client, launch_cmd_cloudinit_option_with_valid_file_is_ok)
EXPECT_THAT(send_command({"launch", "--cloud-init", qPrintable(tmpfile.fileName())}), Eq(mp::ReturnCode::Ok));
}

TEST_F(Client, launch_cmd_cloudinit_option_fails_with_missing_file)
struct BadCloudInitFile : public Client, WithParamInterface<std::string>
{
};

TEST_P(BadCloudInitFile, launch_cmd_cloudinit_option_fails_with_missing_file)
{
std::stringstream cerr_stream;
auto missing_file{"/definitely/missing-file"};

EXPECT_THAT(send_command({"launch", "--cloud-init", missing_file}, trash_stream, cerr_stream),
Eq(mp::ReturnCode::CommandLineError));
EXPECT_NE(std::string::npos, cerr_stream.str().find("No such file")) << "cerr has: " << cerr_stream.str();
EXPECT_NE(std::string::npos, cerr_stream.str().find("Could not load")) << "cerr has: " << cerr_stream.str();
EXPECT_NE(std::string::npos, cerr_stream.str().find(missing_file)) << "cerr has: " << cerr_stream.str();
}

INSTANTIATE_TEST_SUITE_P(Client,
BadCloudInitFile,
Values("/definitely/missing-file", "/dev/null", "/home", "/root/.bashrc"));

TEST_F(Client, launch_cmd_cloudinit_option_fails_no_value)
{
EXPECT_THAT(send_command({"launch", "--cloud-init"}), Eq(mp::ReturnCode::CommandLineError));
Expand Down

0 comments on commit 6dd1800

Please sign in to comment.