diff options
author | A. Wilcox <AWilcox@Wilcox-Tech.com> | 2019-10-12 10:34:54 -0500 |
---|---|---|
committer | A. Wilcox <AWilcox@Wilcox-Tech.com> | 2019-10-12 10:34:54 -0500 |
commit | a36a55c3605bb89125d9d1819a9c32590008ea8f (patch) | |
tree | 74817edc4b676d13c017bee7c0319aad9932e73a | |
parent | 92ff05696506d423111fc7c0ff1e571f64af4615 (diff) | |
download | horizon-a36a55c3605bb89125d9d1819a9c32590008ea8f.tar.gz horizon-a36a55c3605bb89125d9d1819a9c32590008ea8f.tar.bz2 horizon-a36a55c3605bb89125d9d1819a9c32590008ea8f.tar.xz horizon-a36a55c3605bb89125d9d1819a9c32590008ea8f.zip |
hscript: Implement 'repository' key and add tests for it
-rw-r--r-- | hscript/meta.cc | 38 | ||||
-rw-r--r-- | hscript/meta.hh | 10 | ||||
-rw-r--r-- | hscript/script.cc | 82 | ||||
-rw-r--r-- | tests/fixtures/0055-repository-basic.installfile | 7 | ||||
-rw-r--r-- | tests/fixtures/0056-repository-invalid.installfile | 6 | ||||
-rw-r--r-- | tests/spec/validator.rb | 13 |
6 files changed, 147 insertions, 9 deletions
diff --git a/hscript/meta.cc b/hscript/meta.cc index faec607..dc29b0c 100644 --- a/hscript/meta.cc +++ b/hscript/meta.cc @@ -19,7 +19,7 @@ using namespace Horizon::Keys; Key *Hostname::parseFromData(const std::string data, int lineno, int *errors, - int *warnings) { + int *) { std::regex valid_re("[A-Za-z0-9-_.]*"); if(!std::regex_match(data, valid_re)) { if(errors) *errors += 1; @@ -142,3 +142,39 @@ Key *PkgInstall::parseFromData(const std::string data, int lineno, int *errors, } return new PkgInstall(lineno, all_pkgs); } + +Key *Repository::parseFromData(const std::string data, int lineno, int *errors, + int *) { + if(data.empty() || (data[0] != '/' && data.compare(0, 4, "http"))) { + if(errors) *errors += 1; + output_error("installfile:" + std::to_string(lineno), + "repository: must be absolute path or HTTP(S) URL"); + return nullptr; + } + return new Repository(lineno, data); +} + +bool Repository::validate(ScriptOptions) const { + /* TODO XXX: Ensure URL is accessible if networking is available */ + return true; +} + +bool Repository::execute(ScriptOptions opts) const { + /* Runner.Execute.repository. */ + if(opts.test(Simulate)) { + output_info("installfile:" + std::to_string(this->lineno()), + "repository: write '" + this->value() + + "' to /etc/apk/repositories"); + } else { + std::ofstream repo_f("/target/etc/apk/repositories", + std::ios_base::ate); + if(!repo_f) { + output_error("installfile:" + std::to_string(this->lineno()), + "repository: could not open /etc/apk/repositories " + "for writing"); + return false; + } + repo_f << this->value() << std::endl; + } + return true; +} diff --git a/hscript/meta.hh b/hscript/meta.hh index 3574a6f..846158d 100644 --- a/hscript/meta.hh +++ b/hscript/meta.hh @@ -57,7 +57,15 @@ class Firmware : public BooleanKey { class Timezone : public StringKey { }; -class Repository : public Key { +class Repository : public StringKey { +private: + Repository(int _line, const std::string my_url) : + StringKey(_line, my_url) {} +public: + static Key *parseFromData(const std::string data, int lineno, int *errors, + int *warnings); + bool validate(ScriptOptions) const override; + bool execute(ScriptOptions) const override; }; class SigningKey : public Key { diff --git a/hscript/script.cc b/hscript/script.cc index 0583a3c..e92a39f 100644 --- a/hscript/script.cc +++ b/hscript/script.cc @@ -81,6 +81,9 @@ struct Script::ScriptPrivate { /*! Network addressing configuration */ std::vector< std::unique_ptr<Horizon::Keys::NetAddress> > addresses; + /*! APK repositories */ + std::vector< std::unique_ptr<Horizon::Keys::Repository> > repos; + /*! Store +key_obj+ representing the key +key_name+. * @param key_name The name of the key that is being stored. * @param key_obj The Key object associated with the key. @@ -157,6 +160,12 @@ struct Script::ScriptPrivate { ); this->addresses.push_back(std::move(addr)); return true; + } else if(key_name == "repository") { + std::unique_ptr<Keys::Repository> repo( + dynamic_cast<Keys::Repository *>(key_obj) + ); + this->repos.push_back(std::move(repo)); + return true; } else { return false; } @@ -373,6 +382,47 @@ bool Script::validate() const { } } + if(this->internal->repos.size() == 0) { + Keys::Repository *sys_key = dynamic_cast<Keys::Repository *>( + Horizon::Keys::Repository::parseFromData( + "https://distfiles.adelielinux.org/adelie/stable/system", 0, + nullptr, nullptr + ) + ); + if(!sys_key) { + output_error("internal", "failed to create default system repository"); + return false; + } + std::unique_ptr<Keys::Repository> sys_repo(sys_key); + this->internal->repos.push_back(std::move(sys_repo)); + Keys::Repository *user_key = dynamic_cast<Keys::Repository *>( + Horizon::Keys::Repository::parseFromData( + "https://distfiles.adelielinux.org/adelie/stable/user", 0, + nullptr, nullptr + ) + ); + if(!user_key) { + output_error("internal", "failed to create default user repository"); + return false; + } + std::unique_ptr<Keys::Repository> user_repo(user_key); + this->internal->repos.push_back(std::move(user_repo)); + } + + for(auto &repo : this->internal->repos) { + if(!repo->validate(this->opts)) { + failures++; + } + } + + if(this->internal->repos.size() > 10) { + failures++; + output_error("installfile:" + + std::to_string(this->internal->repos[11]->lineno()), + "repository: too many repositories specified", + "You may only specify up to 10 repositories."); + } + output_log("validator", "0", "installfile", std::to_string(failures) + " failure(s).", ""); return (failures == 0); @@ -392,15 +442,33 @@ bool Script::execute() const { return false; } - output_step_start("metadata"); - if(!this->internal->hostname->execute(opts) || - !this->internal->rootpw->execute(opts)) { - output_error("metadata", "The HorizonScript failed to execute", - "Check the log file for more details."); +#define EXECUTE_FAILURE(phase) \ + output_error("pre-metadata", "The HorizonScript failed to execute",\ + "Check the log file for more details.") + + output_step_start("pre-metadata"); + if(!this->internal->hostname->execute(opts)) { + EXECUTE_FAILURE("pre-metadata"); + return false; + } + output_step_end("pre-metadata"); + + output_step_start("pkgdb"); + for(auto &repo : this->internal->repos) { + if(!repo->execute(opts)) { + EXECUTE_FAILURE("pkgdb"); + return false; + } + } + output_step_end("pkgdb"); + + output_step_start("post-metadata"); + if(!this->internal->rootpw->execute(opts)) { + EXECUTE_FAILURE("post-metadata"); return false; } - output_step_end("metadata"); - return false; + output_step_end("post-metadata"); + return true; } } diff --git a/tests/fixtures/0055-repository-basic.installfile b/tests/fixtures/0055-repository-basic.installfile new file mode 100644 index 0000000..b7d8d7f --- /dev/null +++ b/tests/fixtures/0055-repository-basic.installfile @@ -0,0 +1,7 @@ +network false +hostname test.machine +pkginstall adelie-base +rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/ +mount /dev/sda1 / +repository https://distfiles.adelielinux.org/adelie/current/system +repository https://distfiles.adelielinux.org/adelie/current/user diff --git a/tests/fixtures/0056-repository-invalid.installfile b/tests/fixtures/0056-repository-invalid.installfile new file mode 100644 index 0000000..0b393a5 --- /dev/null +++ b/tests/fixtures/0056-repository-invalid.installfile @@ -0,0 +1,6 @@ +network false +hostname test.machine +pkginstall adelie-base +rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/ +mount /dev/sda1 / +repository ftp://anonymous:password@unsupported.ftp.network/pub/adelie/current/system diff --git a/tests/spec/validator.rb b/tests/spec/validator.rb index 4ba83cf..11fd4c4 100644 --- a/tests/spec/validator.rb +++ b/tests/spec/validator.rb @@ -337,6 +337,19 @@ RSpec.describe 'HorizonScript Validation Utility', :type => :aruba do expect(last_command_started).to have_output(/error: .*netaddress.*addresses/) end end + context "for 'repository' key" do + it "succeeds with basic repositories" do + use_fixture '0055-repository-basic.installfile' + run_validate + expect(last_command_started).to have_output(PARSER_SUCCESS) + expect(last_command_started).to have_output(VALIDATOR_SUCCESS) + end + it "fails with invalid repository URL" do + use_fixture '0056-repository-invalid.installfile' + run_validate + expect(last_command_started).to have_output(/error: .*repository/) + end + end end context "unique keys" do # Runner.Validate.network. |