|
|
@@ -53,7 +53,7 @@ BEGIN {
|
|
|
# provisioner keeps them rather than anywhere tCMS is told about.
|
|
|
$ENV{TROG_PROVISIONER_CONFIG} = "$ROOT/etc";
|
|
|
File::Path::make_path("$ROOT/etc/recipes.d");
|
|
|
- open( my $recipe, '>', "$ROOT/etc/recipes.d/guest.example.com.yaml" ) or die $!;
|
|
|
+ open( my $recipe, '>', "$ROOT/etc/recipes.d/guest.test.test.yaml" ) or die $!;
|
|
|
print {$recipe} "---\n_global:\n registrar: secret:x/y/z\n";
|
|
|
close($recipe) or die $!;
|
|
|
|
|
|
@@ -84,7 +84,7 @@ sub write_config {
|
|
|
|
|
|
require_ok('Trog::DataSource::ProvisionedVirt') or BAIL_OUT("Can't find SUT");
|
|
|
|
|
|
-Trog::Auth::useradd( 'admin', 'The Admin', 'hunter2', ['admin'], 'admin@example.com' )
|
|
|
+Trog::Auth::useradd( 'admin', 'The Admin', 'hunter2', ['admin'], 'admin@test.test' )
|
|
|
or BAIL_OUT('could not make a user to test with');
|
|
|
|
|
|
my $log = Test::MockModule->new('Trog::DataSource::ProvisionedVirt');
|
|
|
@@ -103,7 +103,7 @@ $log->redefine(
|
|
|
|
|
|
# Nor reaches a hypervisor.
|
|
|
my $virt = Test::MockModule->new('Trog::DataSource::Virt');
|
|
|
-$virt->redefine( is_self => sub { return $_[0] eq 'thisserver.example.com' ? 1 : 0 } );
|
|
|
+$virt->redefine( is_self => sub { return $_[0] eq 'thisserver.test.test' ? 1 : 0 } );
|
|
|
|
|
|
write_config( trog_provisioner => "$ROOT/trog-provisioner" );
|
|
|
|
|
|
@@ -145,10 +145,10 @@ subtest 'the recipe lands on the guest' => sub {
|
|
|
$virt->redefine(
|
|
|
posts => sub {
|
|
|
return (
|
|
|
- { title => 'guest.example.com', domain => 'guest.example.com', is_self => 0 },
|
|
|
- { title => 'norecipe.example.com', domain => 'norecipe.example.com', is_self => 0 },
|
|
|
- { title => 'thisserver.example.com', domain => 'thisserver.example.com', is_self => 1 },
|
|
|
- { title => 'a hypervisor', unreachable => 1, state => 'nope' },
|
|
|
+ { title => 'guest.test.test', domain => 'guest.test.test', is_self => 0 },
|
|
|
+ { title => 'norecipe.test.test', domain => 'norecipe.test.test', is_self => 0 },
|
|
|
+ { title => 'thisserver.test.test', domain => 'thisserver.test.test', is_self => 1 },
|
|
|
+ { title => 'a hypervisor', unreachable => 1, state => 'nope' },
|
|
|
);
|
|
|
}
|
|
|
);
|
|
|
@@ -156,18 +156,18 @@ subtest 'the recipe lands on the guest' => sub {
|
|
|
my @posts = Trog::DataSource::ProvisionedVirt::posts( {}, {} );
|
|
|
is( scalar(@posts), 4, 'every guest Virt listed is still listed' );
|
|
|
|
|
|
- my ($provisioned) = grep { ( $_->{domain} // '' ) eq 'guest.example.com' } @posts;
|
|
|
+ my ($provisioned) = grep { ( $_->{domain} // '' ) eq 'guest.test.test' } @posts;
|
|
|
ok( $provisioned->{has_recipe}, 'the one with a recipe says so' );
|
|
|
- like( $provisioned->{recipe}, qr/registrar/, 'and carries the recipe itself' );
|
|
|
- like( $provisioned->{recipe_path}, qr{recipes\.d/guest\.example\.com\.yaml$}, 'and where it came from' );
|
|
|
+ like( $provisioned->{recipe}, qr/registrar/, 'and carries the recipe itself' );
|
|
|
+ like( $provisioned->{recipe_path}, qr{recipes\.d/guest\.test\.test\.yaml$}, 'and where it came from' );
|
|
|
is( $provisioned->{can_reprovision}, 1, 'and may be reprovisioned' );
|
|
|
|
|
|
- my ($bare) = grep { ( $_->{domain} // '' ) eq 'norecipe.example.com' } @posts;
|
|
|
+ my ($bare) = grep { ( $_->{domain} // '' ) eq 'norecipe.test.test' } @posts;
|
|
|
ok( !$bare->{has_recipe}, 'a guest with no recipe says so' );
|
|
|
is( $bare->{can_reprovision}, 0, 'and may not be reprovisioned' );
|
|
|
ok( exists $bare->{title}, 'but is listed all the same, since plenty of guests were not built by this' );
|
|
|
|
|
|
- my ($self) = grep { ( $_->{domain} // '' ) eq 'thisserver.example.com' } @posts;
|
|
|
+ my ($self) = grep { ( $_->{domain} // '' ) eq 'thisserver.test.test' } @posts;
|
|
|
is( $self->{can_reprovision}, 0, 'the server drawing the page may never be reprovisioned' );
|
|
|
|
|
|
my ($dead) = grep { $_->{unreachable} } @posts;
|
|
|
@@ -175,21 +175,21 @@ subtest 'the recipe lands on the guest' => sub {
|
|
|
};
|
|
|
|
|
|
subtest 'what it refuses to reprovision' => sub {
|
|
|
- my ( $ok, $why ) = reprovision( domain => 'thisserver.example.com' );
|
|
|
+ my ( $ok, $why ) = reprovision( domain => 'thisserver.test.test' );
|
|
|
is( $ok, 0, 'the server it is running on' );
|
|
|
like( $why, qr/this[ ]server/, 'and says why' );
|
|
|
is_deeply( \@SPAWNED, [], 'without running anything' );
|
|
|
|
|
|
- ( $ok, $why ) = reprovision( domain => 'norecipe.example.com' );
|
|
|
+ ( $ok, $why ) = reprovision( domain => 'norecipe.test.test' );
|
|
|
is( $ok, 0, 'a guest with no recipe' );
|
|
|
like( $why, qr/no[ ]recipe/, 'and says why' );
|
|
|
|
|
|
- ( $ok, $why ) = reprovision( domain => 'guest.example.com', passphrase => '' );
|
|
|
+ ( $ok, $why ) = reprovision( domain => 'guest.test.test', passphrase => '' );
|
|
|
is( $ok, 0, 'a run with no passphrase, which the provisioner would just hang waiting for' );
|
|
|
like( $why, qr/passphrase/, 'and says why' );
|
|
|
|
|
|
# The name reaches the filesystem and an argument list.
|
|
|
- foreach my $bad ( '../../etc/passwd', 'guest;rm -rf /', 'guest example.com', '', 'a' x 300, '.hidden' ) {
|
|
|
+ foreach my $bad ( '../../etc/passwd', 'guest;rm -rf /', 'guest test.test', '', 'a' x 300, '.hidden' ) {
|
|
|
my ( $refused, $message ) = reprovision( domain => $bad );
|
|
|
is( $refused, 0, "'$bad' is refused" );
|
|
|
like( $message, qr/bad[ ]guest[ ]name|no[ ]recipe/, '...before anything is run' );
|
|
|
@@ -199,21 +199,21 @@ subtest 'what it refuses to reprovision' => sub {
|
|
|
};
|
|
|
|
|
|
subtest 'what it would run' => sub {
|
|
|
- my ( $ok, $why ) = reprovision( domain => 'guest.example.com' );
|
|
|
+ my ( $ok, $why ) = reprovision( domain => 'guest.test.test' );
|
|
|
is( $ok, 1, 'a guest with a recipe is accepted' ) or diag($why);
|
|
|
like( $why, qr/started/, 'and reports that it started rather than that it finished' );
|
|
|
|
|
|
is( scalar(@SPAWNED), 1, 'exactly one run' );
|
|
|
my $run = $SPAWNED[0];
|
|
|
- is( $run->{domain}, 'guest.example.com', 'for the guest asked about' );
|
|
|
- is( $run->{user}, 'admin', 'recording who asked' );
|
|
|
+ is( $run->{domain}, 'guest.test.test', 'for the guest asked about' );
|
|
|
+ is( $run->{user}, 'admin', 'recording who asked' );
|
|
|
|
|
|
# One program does the whole of it now: bin/provision generates the guest's
|
|
|
# configuration from its recipe and then builds the machine.
|
|
|
is( $run->{dir}, "$ROOT/trog-provisioner", 'run from the checkout' );
|
|
|
like( $run->{command}[0], qr{/bin/provision$}, 'and it is bin/provision' );
|
|
|
- is( $run->{command}[1], '--credentials', 'told that its passwords are coming on stdin' );
|
|
|
- is( $run->{command}[2], 'guest.example.com', 'and passed the guest as an argument' );
|
|
|
+ is( $run->{command}[1], '--credentials', 'told that its passwords are coming on stdin' );
|
|
|
+ is( $run->{command}[2], 'guest.test.test', 'and passed the guest as an argument' );
|
|
|
|
|
|
# Arguments, not a command line: there is no shell between us and this, so a
|
|
|
# guest name can never be read as one.
|
|
|
@@ -225,19 +225,19 @@ subtest 'a stored passphrase, and a code instead of one' => sub {
|
|
|
|
|
|
# Nothing stored yet, so the form asks for the passphrase and offers to keep
|
|
|
# it -- there is a vault key in this sandbox, so keeping it is on the table.
|
|
|
- $virt->redefine( posts => sub { return ( { title => 'guest.example.com', domain => 'guest.example.com', is_self => 0 } ) } );
|
|
|
+ $virt->redefine( posts => sub { return ( { title => 'guest.test.test', domain => 'guest.test.test', is_self => 0 } ) } );
|
|
|
my ($post) = Trog::DataSource::ProvisionedVirt::posts( {}, { user => 'admin' } );
|
|
|
is( $post->{passphrase_remembered}, 0, 'with nothing stored the form asks for the passphrase' );
|
|
|
is( $post->{can_remember}, 1, 'and can offer to remember it' );
|
|
|
|
|
|
# A code is worth nothing when there is nothing stored to unlock: it is
|
|
|
# proof somebody is here, not a password.
|
|
|
- my ( $ok, $why ) = reprovision( domain => 'guest.example.com', passphrase => undef, totp => '123456' );
|
|
|
+ my ( $ok, $why ) = reprovision( domain => 'guest.test.test', passphrase => undef, totp => '123456' );
|
|
|
is( $ok, 0, 'a code with nothing stored behind it does not provision' );
|
|
|
is_deeply( \@SPAWNED, [], 'having run nothing' );
|
|
|
|
|
|
# Reprovision the old way, and ask for it to be kept.
|
|
|
- ( $ok, $why ) = reprovision( domain => 'guest.example.com', passphrase => 'correct horse', remember => 1 );
|
|
|
+ ( $ok, $why ) = reprovision( domain => 'guest.test.test', passphrase => 'correct horse', remember => 1 );
|
|
|
is( $ok, 1, 'a typed passphrase still provisions' ) or diag($why);
|
|
|
is( $SPAWNED[0]{credentials}{keepass}, 'correct horse', 'and is what reaches the provisioner' );
|
|
|
|
|
|
@@ -246,17 +246,17 @@ subtest 'a stored passphrase, and a code instead of one' => sub {
|
|
|
|
|
|
# And now the point of all of it: a code, spent, exchanged for what was
|
|
|
# stored. Enrol first -- a code is only meaningful for somebody enrolled.
|
|
|
- my ( $uri, undef, undef, $message, $totp ) = Trog::Auth::totp( 'admin', 'example.com' );
|
|
|
+ my ( $uri, undef, undef, $message, $totp ) = Trog::Auth::totp( 'admin', 'test.test' );
|
|
|
ok( $uri, 'the user is enrolled' ) or diag($message);
|
|
|
my $code = $totp->expected_totp_code( time() );
|
|
|
|
|
|
- ( $ok, $why ) = reprovision( domain => 'guest.example.com', passphrase => undef, totp => $code );
|
|
|
+ ( $ok, $why ) = reprovision( domain => 'guest.test.test', passphrase => undef, totp => $code );
|
|
|
is( $ok, 1, 'a code provisions' ) or diag($why);
|
|
|
is( $SPAWNED[0]{credentials}{keepass}, 'correct horse', 'handing the provisioner the passphrase that was stored' );
|
|
|
|
|
|
# Spent, so it is worth this one reprovision and not every reprovision
|
|
|
# somebody can click inside the window.
|
|
|
- ( $ok, $why ) = reprovision( domain => 'guest.example.com', passphrase => undef, totp => $code );
|
|
|
+ ( $ok, $why ) = reprovision( domain => 'guest.test.test', passphrase => undef, totp => $code );
|
|
|
is( $ok, 0, 'and cannot be used again' );
|
|
|
like( $why, qr/already[ ]been[ ]used/, 'saying so' );
|
|
|
is_deeply( \@SPAWNED, [], 'without running a second one' );
|
|
|
@@ -267,7 +267,7 @@ subtest 'a stored passphrase, and a code instead of one' => sub {
|
|
|
subtest 'the sudo password on the hypervisor' => sub {
|
|
|
no warnings qw{once};
|
|
|
|
|
|
- $virt->redefine( posts => sub { return ( { title => 'guest.example.com', domain => 'guest.example.com', is_self => 0 } ) } );
|
|
|
+ $virt->redefine( posts => sub { return ( { title => 'guest.test.test', domain => 'guest.test.test', is_self => 0 } ) } );
|
|
|
Trog::Vault::forget( 'admin', $Trog::DataSource::ProvisionedVirt::secret_name );
|
|
|
Trog::Vault::forget( 'admin', $Trog::DataSource::ProvisionedVirt::sudo_name );
|
|
|
|
|
|
@@ -276,29 +276,29 @@ subtest 'the sudo password on the hypervisor' => sub {
|
|
|
|
|
|
# The ordinary case, and the reason the field is not required: the login on
|
|
|
# the hypervisor has passwordless sudo, so there is nothing to send.
|
|
|
- my ( $ok, $why ) = reprovision( domain => 'guest.example.com', passphrase => 'correct horse' );
|
|
|
+ my ( $ok, $why ) = reprovision( domain => 'guest.test.test', passphrase => 'correct horse' );
|
|
|
is( $ok, 1, 'a reprovision with no sudo password still runs' ) or diag($why);
|
|
|
ok( !exists $SPAWNED[0]{credentials}{sudo}, 'and sends none, rather than sending an empty one' );
|
|
|
|
|
|
# And the case this is for: a hypervisor that wants one. sudo over ssh has
|
|
|
# no terminal to ask at, so the run would otherwise die minutes in.
|
|
|
- ( $ok, $why ) = reprovision( domain => 'guest.example.com', passphrase => 'correct horse', sudo => 'hunter2' );
|
|
|
+ ( $ok, $why ) = reprovision( domain => 'guest.test.test', passphrase => 'correct horse', sudo => 'hunter2' );
|
|
|
is( $ok, 1, 'one with a sudo password runs too' ) or diag($why);
|
|
|
is( $SPAWNED[0]{credentials}{sudo}, 'hunter2', 'and it reaches the provisioner' );
|
|
|
is( $SPAWNED[0]{credentials}{keepass}, 'correct horse', 'alongside the passphrase, not instead of it' );
|
|
|
|
|
|
# Kept, so the next run is a code and neither has to be typed again.
|
|
|
- ( $ok, $why ) = reprovision( domain => 'guest.example.com', passphrase => 'correct horse', sudo => 'hunter2', remember => 1 );
|
|
|
+ ( $ok, $why ) = reprovision( domain => 'guest.test.test', passphrase => 'correct horse', sudo => 'hunter2', remember => 1 );
|
|
|
is( $ok, 1, 'both can be remembered' ) or diag($why);
|
|
|
($post) = Trog::DataSource::ProvisionedVirt::posts( {}, { user => 'admin' } );
|
|
|
is( $post->{passphrase_remembered}, 1, 'after which the passphrase is stored' );
|
|
|
is( $post->{sudo_remembered}, 1, 'and so is the sudo password' );
|
|
|
|
|
|
- my ( undef, undef, undef, undef, $totp ) = Trog::Auth::totp( 'admin', 'example.com' );
|
|
|
+ my ( undef, undef, undef, undef, $totp ) = Trog::Auth::totp( 'admin', 'test.test' );
|
|
|
require Trog::SQLite;
|
|
|
Trog::SQLite::dbh( 'schema/auth.schema', 'config/auth.db' )->do("DELETE FROM totp_spent WHERE username='admin'");
|
|
|
|
|
|
- ( $ok, $why ) = reprovision( domain => 'guest.example.com', passphrase => undef, totp => $totp->expected_totp_code( time() ) );
|
|
|
+ ( $ok, $why ) = reprovision( domain => 'guest.test.test', passphrase => undef, totp => $totp->expected_totp_code( time() ) );
|
|
|
is( $ok, 1, 'a code unlocks the pair' ) or diag($why);
|
|
|
is( $SPAWNED[0]{credentials}{keepass}, 'correct horse', 'the passphrase' );
|
|
|
is( $SPAWNED[0]{credentials}{sudo}, 'hunter2', 'and the sudo password' );
|
|
|
@@ -306,7 +306,7 @@ subtest 'the sudo password on the hypervisor' => sub {
|
|
|
# Typed beats stored: somebody typing it has a reason to, and it is usually
|
|
|
# that the stored one stopped working.
|
|
|
Trog::SQLite::dbh( 'schema/auth.schema', 'config/auth.db' )->do("DELETE FROM totp_spent WHERE username='admin'");
|
|
|
- ( $ok, $why ) = reprovision( domain => 'guest.example.com', passphrase => undef, sudo => 'changed it', totp => $totp->expected_totp_code( time() ) );
|
|
|
+ ( $ok, $why ) = reprovision( domain => 'guest.test.test', passphrase => undef, sudo => 'changed it', totp => $totp->expected_totp_code( time() ) );
|
|
|
is( $ok, 1, 'a code and a typed sudo password together' ) or diag($why);
|
|
|
is( $SPAWNED[0]{credentials}{sudo}, 'changed it', 'send what was typed' );
|
|
|
|
|
|
@@ -319,12 +319,12 @@ subtest 'a password with a line break in it is refused' => sub {
|
|
|
# One 'name: value' per line is the format on the far side, so a newline in
|
|
|
# a value is a second line -- and the second line could name a credential
|
|
|
# nobody asked us to send.
|
|
|
- my ( $ok, $why ) = reprovision( domain => 'guest.example.com', passphrase => "correct horse\nsudo: injected" );
|
|
|
+ my ( $ok, $why ) = reprovision( domain => 'guest.test.test', passphrase => "correct horse\nsudo: injected" );
|
|
|
is( $ok, 0, 'a passphrase carrying a line break does not run' );
|
|
|
like( $why, qr/line[ ]break/, 'saying so' );
|
|
|
is_deeply( \@SPAWNED, [], 'having run nothing' );
|
|
|
|
|
|
- ( $ok, $why ) = reprovision( domain => 'guest.example.com', passphrase => 'correct horse', sudo => "hunter2\nkeepass: not this" );
|
|
|
+ ( $ok, $why ) = reprovision( domain => 'guest.test.test', passphrase => 'correct horse', sudo => "hunter2\nkeepass: not this" );
|
|
|
is( $ok, 0, 'and neither does a sudo password carrying one' );
|
|
|
like( $why, qr/line[ ]break/, 'saying so too' );
|
|
|
is_deeply( \@SPAWNED, [], 'having run nothing' );
|
|
|
@@ -337,7 +337,7 @@ subtest 'and when the vault key has gone' => sub {
|
|
|
# consequence of rebuilding one rather than a disaster. What must not
|
|
|
# happen is the page going on asking for a code it cannot honour.
|
|
|
Trog::Vault::set( 'admin', $Trog::DataSource::ProvisionedVirt::secret_name, 'correct horse' );
|
|
|
- $virt->redefine( posts => sub { return ( { title => 'guest.example.com', domain => 'guest.example.com', is_self => 0 } ) } );
|
|
|
+ $virt->redefine( posts => sub { return ( { title => 'guest.test.test', domain => 'guest.test.test', is_self => 0 } ) } );
|
|
|
|
|
|
my ($post) = Trog::DataSource::ProvisionedVirt::posts( {}, { user => 'admin' } );
|
|
|
is( $post->{passphrase_remembered}, 1, 'with the key here, the form asks for a code' );
|
|
|
@@ -350,7 +350,7 @@ subtest 'and when the vault key has gone' => sub {
|
|
|
|
|
|
# Posted at directly, as somebody would from a page drawn a moment before
|
|
|
# the key went away.
|
|
|
- my ( undef, undef, undef, undef, $totp ) = Trog::Auth::totp( 'admin', 'example.com' );
|
|
|
+ my ( undef, undef, undef, undef, $totp ) = Trog::Auth::totp( 'admin', 'test.test' );
|
|
|
|
|
|
# The subtest above spent this window's codes. Standing here for thirty
|
|
|
# seconds would say the same thing and cost thirty seconds.
|
|
|
@@ -358,7 +358,7 @@ subtest 'and when the vault key has gone' => sub {
|
|
|
Trog::SQLite::dbh( 'schema/auth.schema', 'config/auth.db' )->do("DELETE FROM totp_spent WHERE username='admin'");
|
|
|
|
|
|
my $code = $totp->expected_totp_code( time() );
|
|
|
- my ( $ok, $why ) = reprovision( domain => 'guest.example.com', passphrase => undef, totp => $code );
|
|
|
+ my ( $ok, $why ) = reprovision( domain => 'guest.test.test', passphrase => undef, totp => $code );
|
|
|
is( $ok, 0, 'a code is refused rather than exploding' );
|
|
|
like( $why, qr/can[ ]open/, 'saying the passphrase cannot be opened' );
|
|
|
like( $why, qr{/secrets}, 'and where to go about it' );
|
|
|
@@ -370,7 +370,7 @@ subtest 'and when the vault key has gone' => sub {
|
|
|
( $ok, $why ) = Trog::Auth::spend_totp( 'admin', $code );
|
|
|
is( $ok, 1, 'the code was not spent on being told no' ) or diag($why);
|
|
|
|
|
|
- ( $ok, $why ) = reprovision( domain => 'guest.example.com', passphrase => 'typed it again', remember => 1 );
|
|
|
+ ( $ok, $why ) = reprovision( domain => 'guest.test.test', passphrase => 'typed it again', remember => 1 );
|
|
|
is( $ok, 1, 'and the passphrase still provisions' ) or diag($why);
|
|
|
is( $SPAWNED[0]{credentials}{keepass}, 'typed it again', 'with what was typed' );
|
|
|
|
|
|
@@ -381,12 +381,12 @@ subtest 'and when the vault key has gone' => sub {
|
|
|
subtest 'without the provisioner configured it is just Virt' => sub {
|
|
|
write_config();
|
|
|
|
|
|
- my ( $ok, $why ) = reprovision( domain => 'guest.example.com' );
|
|
|
+ my ( $ok, $why ) = reprovision( domain => 'guest.test.test' );
|
|
|
is( $ok, 0, 'nothing to run' );
|
|
|
like( $why, qr/not[ ]configured/, 'and says so plainly' );
|
|
|
is_deeply( \@SPAWNED, [], 'having run nothing' );
|
|
|
|
|
|
- $virt->redefine( posts => sub { return ( { title => 'guest.example.com', domain => 'guest.example.com', is_self => 0 } ) } );
|
|
|
+ $virt->redefine( posts => sub { return ( { title => 'guest.test.test', domain => 'guest.test.test', is_self => 0 } ) } );
|
|
|
my ($post) = Trog::DataSource::ProvisionedVirt::posts( {}, {} );
|
|
|
ok( !$post->{has_recipe}, 'the listing still works' );
|
|
|
is( $post->{can_reprovision}, 0, 'it simply offers no button' );
|
|
|
@@ -394,7 +394,7 @@ subtest 'without the provisioner configured it is just Virt' => sub {
|
|
|
# A path that is not there is a typo, and better found here than halfway
|
|
|
# through a reprovision.
|
|
|
write_config( trog_provisioner => "$ROOT/nonesuch" );
|
|
|
- ( $ok, $why ) = reprovision( domain => 'guest.example.com' );
|
|
|
+ ( $ok, $why ) = reprovision( domain => 'guest.test.test' );
|
|
|
is( $ok, 0, 'a configured path which is not there is refused' );
|
|
|
like( $why, qr/not[ ]configured/, 'the same as never having configured one' );
|
|
|
|
|
|
@@ -405,23 +405,23 @@ subtest 'the log is read back onto the page' => sub {
|
|
|
no warnings qw{once};
|
|
|
|
|
|
File::Path::make_path("$ROOT/logs/reprovision");
|
|
|
- open( my $fh, '>', "$ROOT/logs/reprovision/guest.example.com.log" ) or die $!;
|
|
|
+ open( my $fh, '>', "$ROOT/logs/reprovision/guest.test.test.log" ) or die $!;
|
|
|
print {$fh} ( 'x' x 9000 ) . "\n=== finished ===\n";
|
|
|
close($fh) or die $!;
|
|
|
|
|
|
- my $tail = Trog::DataSource::ProvisionedVirt::log_tail('guest.example.com');
|
|
|
+ my $tail = Trog::DataSource::ProvisionedVirt::log_tail('guest.test.test');
|
|
|
ok( length($tail) <= $Trog::DataSource::ProvisionedVirt::log_tail_bytes, 'only the tail of it' );
|
|
|
like( $tail, qr/===[ ]finished[ ]===/, 'which is the part that says how it went' );
|
|
|
|
|
|
- is( Trog::DataSource::ProvisionedVirt::log_tail('norecipe.example.com'), undef, 'nothing when it has never run' );
|
|
|
- is( Trog::DataSource::ProvisionedVirt::log_tail('../../etc/passwd'), undef, 'and a name that is not one reads nothing' );
|
|
|
+ is( Trog::DataSource::ProvisionedVirt::log_tail('norecipe.test.test'), undef, 'nothing when it has never run' );
|
|
|
+ is( Trog::DataSource::ProvisionedVirt::log_tail('../../etc/passwd'), undef, 'and a name that is not one reads nothing' );
|
|
|
};
|
|
|
|
|
|
subtest 'the state a reprovision leaves behind' => sub {
|
|
|
no warnings qw{once};
|
|
|
File::Path::make_path("$ROOT/logs/reprovision");
|
|
|
|
|
|
- my $status = "$ROOT/logs/reprovision/guest.example.com.status";
|
|
|
+ my $status = "$ROOT/logs/reprovision/guest.test.test.status";
|
|
|
my $write = sub {
|
|
|
open( my $fh, '>', $status ) or die $!;
|
|
|
print {$fh} join( '', map { "$_\n" } @_ );
|
|
|
@@ -431,18 +431,18 @@ subtest 'the state a reprovision leaves behind' => sub {
|
|
|
# Nothing waits on the process which does the work, so this file is the
|
|
|
# whole of what it can say for itself.
|
|
|
$write->(qw{state=ok started=100 finished=200 exit=0 user=admin});
|
|
|
- my $got = Trog::DataSource::ProvisionedVirt::status('guest.example.com');
|
|
|
+ my $got = Trog::DataSource::ProvisionedVirt::status('guest.test.test');
|
|
|
is( $got->{state}, 'ok', 'a finished run reads back as finished' );
|
|
|
is( $got->{exit}, '0', 'with what it exited' );
|
|
|
is( $got->{user}, 'admin', 'and who asked for it' );
|
|
|
is( $got->{finished}, '200', 'and when it stopped' );
|
|
|
|
|
|
$write->(qw{state=failed exit=3 failed=/x/bin/provision});
|
|
|
- is( Trog::DataSource::ProvisionedVirt::status('guest.example.com')->{state}, 'failed', 'a failed one reads back failed' );
|
|
|
+ is( Trog::DataSource::ProvisionedVirt::status('guest.test.test')->{state}, 'failed', 'a failed one reads back failed' );
|
|
|
|
|
|
# A live pid means it really is going on. Ours is alive by definition.
|
|
|
$write->( 'state=running', "pid=$$", 'started=100', 'user=admin' );
|
|
|
- is( Trog::DataSource::ProvisionedVirt::status('guest.example.com')->{state}, 'running', 'a run whose process is alive is running' );
|
|
|
+ is( Trog::DataSource::ProvisionedVirt::status('guest.test.test')->{state}, 'running', 'a run whose process is alive is running' );
|
|
|
|
|
|
# And a dead one means it stopped without saying so, which is the case that
|
|
|
# would otherwise leave the page claiming a provision forever.
|
|
|
@@ -450,20 +450,20 @@ subtest 'the state a reprovision leaves behind' => sub {
|
|
|
$dead++ while kill( 0, $dead ) && $dead < 4194304;
|
|
|
$write->( 'state=running', "pid=$dead", 'started=100' );
|
|
|
is(
|
|
|
- Trog::DataSource::ProvisionedVirt::status('guest.example.com')->{state},
|
|
|
+ Trog::DataSource::ProvisionedVirt::status('guest.test.test')->{state},
|
|
|
'interrupted',
|
|
|
'a run whose process is gone reads as interrupted, not as still going'
|
|
|
);
|
|
|
|
|
|
$write->('state=running');
|
|
|
- is( Trog::DataSource::ProvisionedVirt::status('guest.example.com')->{state}, 'interrupted', 'and so does one with no pid at all' );
|
|
|
+ is( Trog::DataSource::ProvisionedVirt::status('guest.test.test')->{state}, 'interrupted', 'and so does one with no pid at all' );
|
|
|
|
|
|
# Half a file is not a status.
|
|
|
$write->('garbage');
|
|
|
- is( Trog::DataSource::ProvisionedVirt::status('guest.example.com'), undef, 'an unparseable status is no status' );
|
|
|
+ is( Trog::DataSource::ProvisionedVirt::status('guest.test.test'), undef, 'an unparseable status is no status' );
|
|
|
|
|
|
- is( Trog::DataSource::ProvisionedVirt::status('never.example.com'), undef, 'nothing for a guest that has never run' );
|
|
|
- is( Trog::DataSource::ProvisionedVirt::status('../../etc/passwd'), undef, 'and a name that is not one reads nothing' );
|
|
|
+ is( Trog::DataSource::ProvisionedVirt::status('never.test.test'), undef, 'nothing for a guest that has never run' );
|
|
|
+ is( Trog::DataSource::ProvisionedVirt::status('../../etc/passwd'), undef, 'and a name that is not one reads nothing' );
|
|
|
|
|
|
unlink($status);
|
|
|
};
|
|
|
@@ -472,27 +472,27 @@ subtest 'the listing says what is going on' => sub {
|
|
|
no warnings qw{once};
|
|
|
File::Path::make_path("$ROOT/logs/reprovision");
|
|
|
|
|
|
- my $status = "$ROOT/logs/reprovision/guest.example.com.status";
|
|
|
- open( my $out, '>', "$ROOT/logs/reprovision/guest.example.com.log" ) or die $!;
|
|
|
+ my $status = "$ROOT/logs/reprovision/guest.test.test.status";
|
|
|
+ open( my $out, '>', "$ROOT/logs/reprovision/guest.test.test.log" ) or die $!;
|
|
|
print {$out} "some output\n";
|
|
|
close($out) or die $!;
|
|
|
|
|
|
- $virt->redefine( posts => sub { return ( { title => 'guest.example.com', domain => 'guest.example.com', is_self => 0 } ) } );
|
|
|
+ $virt->redefine( posts => sub { return ( { title => 'guest.test.test', domain => 'guest.test.test', is_self => 0 } ) } );
|
|
|
|
|
|
open( my $fh, '>', $status ) or die $!;
|
|
|
print {$fh} "state=running\npid=$$\nstarted=100\nuser=admin\n";
|
|
|
close($fh) or die $!;
|
|
|
|
|
|
my ($post) = Trog::DataSource::ProvisionedVirt::posts( {}, {} );
|
|
|
- is( $post->{reprovision_state}, 'running', 'the guest says it is reprovisioning' );
|
|
|
- is( $post->{reprovision_status}, 'reprovisioning', 'in words a person reads' );
|
|
|
- is( $post->{is_reprovisioning}, 1, 'and is flagged as busy' );
|
|
|
- is( $post->{reprovision_by}, 'admin', 'naming who started it' );
|
|
|
- is( $post->{can_reprovision}, 0, 'and offers no button while one is going on' );
|
|
|
- is( $post->{reprovision_log_href}, '/guest/reprovision/log/guest.example.com', 'with a link to read the log' );
|
|
|
+ is( $post->{reprovision_state}, 'running', 'the guest says it is reprovisioning' );
|
|
|
+ is( $post->{reprovision_status}, 'reprovisioning', 'in words a person reads' );
|
|
|
+ is( $post->{is_reprovisioning}, 1, 'and is flagged as busy' );
|
|
|
+ is( $post->{reprovision_by}, 'admin', 'naming who started it' );
|
|
|
+ is( $post->{can_reprovision}, 0, 'and offers no button while one is going on' );
|
|
|
+ is( $post->{reprovision_log_href}, '/guest/reprovision/log/guest.test.test', 'with a link to read the log' );
|
|
|
|
|
|
# Starting a second one is refused for the same reason.
|
|
|
- my ( $ok, $why ) = reprovision( domain => 'guest.example.com' );
|
|
|
+ my ( $ok, $why ) = reprovision( domain => 'guest.test.test' );
|
|
|
is( $ok, 0, 'and a second run is refused while the first is going' );
|
|
|
like( $why, qr/already[ ]running/, 'saying so' );
|
|
|
is_deeply( \@SPAWNED, [], 'having started nothing' );
|
|
|
@@ -517,20 +517,20 @@ subtest 'the listing says what is going on' => sub {
|
|
|
subtest 'reading the log' => sub {
|
|
|
no warnings qw{once};
|
|
|
|
|
|
- is( Trog::DataSource::ProvisionedVirt::log_for('never.example.com'), undef, 'nothing when there has been no run' );
|
|
|
- is( Trog::DataSource::ProvisionedVirt::log_for('../../etc/passwd'), undef, 'and a name that is not one reads nothing' );
|
|
|
+ is( Trog::DataSource::ProvisionedVirt::log_for('never.test.test'), undef, 'nothing when there has been no run' );
|
|
|
+ is( Trog::DataSource::ProvisionedVirt::log_for('../../etc/passwd'), undef, 'and a name that is not one reads nothing' );
|
|
|
|
|
|
- open( my $fh, '>', "$ROOT/logs/reprovision/guest.example.com.log" ) or die $!;
|
|
|
+ open( my $fh, '>', "$ROOT/logs/reprovision/guest.test.test.log" ) or die $!;
|
|
|
print {$fh} "the whole log\n";
|
|
|
close($fh) or die $!;
|
|
|
- like( Trog::DataSource::ProvisionedVirt::log_for('guest.example.com'), qr/the[ ]whole[ ]log/, 'and the whole of it when there has' );
|
|
|
+ like( Trog::DataSource::ProvisionedVirt::log_for('guest.test.test'), qr/the[ ]whole[ ]log/, 'and the whole of it when there has' );
|
|
|
|
|
|
# A provisioner can be chatty, and this goes out in one response.
|
|
|
local $Trog::DataSource::ProvisionedVirt::log_max_bytes = 64;
|
|
|
- open( $fh, '>', "$ROOT/logs/reprovision/guest.example.com.log" ) or die $!;
|
|
|
+ open( $fh, '>', "$ROOT/logs/reprovision/guest.test.test.log" ) or die $!;
|
|
|
print {$fh} ( 'x' x 500 ) . "END\n";
|
|
|
close($fh) or die $!;
|
|
|
- my $capped = Trog::DataSource::ProvisionedVirt::log_for('guest.example.com');
|
|
|
+ my $capped = Trog::DataSource::ProvisionedVirt::log_for('guest.test.test');
|
|
|
like( $capped, qr/truncated/, 'a huge one is truncated' );
|
|
|
like( $capped, qr/END/, 'keeping the end, which is where the answer is' );
|
|
|
};
|
|
|
@@ -565,7 +565,7 @@ subtest 'the route' => sub {
|
|
|
# The passphrase must not survive the request: this hash gets cloned, logged
|
|
|
# around and handed to renderers.
|
|
|
@SPAWNED = ();
|
|
|
- my $query = { user => 'admin', user_acls => ['admin'], tpsgi => $tpsgi, guest => 'guest.example.com', passphrase => 'hunter2', sudo => 'letmein', to => '/vms' };
|
|
|
+ my $query = { user => 'admin', user_acls => ['admin'], tpsgi => $tpsgi, guest => 'guest.test.test', passphrase => 'hunter2', sudo => 'letmein', to => '/vms' };
|
|
|
Trog::Routes::HTML::guest_reprovision($query);
|
|
|
is( scalar(@SPAWNED), 1, 'an admin gets their run' );
|
|
|
is( $SPAWNED[0]{credentials}{keepass}, 'hunter2', 'the passphrase reaches the provisioner' );
|
|
|
@@ -585,7 +585,7 @@ subtest 'the route' => sub {
|
|
|
$res = Trog::Routes::HTML::guest_reprovision_log( { user => 'bob', user_acls => ['public'], tpsgi => $tpsgi } );
|
|
|
is( $res->[0], 403, 'a non-admin cannot read it' );
|
|
|
|
|
|
- $res = Trog::Routes::HTML::guest_reprovision_log( { user => 'admin', user_acls => ['admin'], tpsgi => $tpsgi, guest => 'never.example.com' } );
|
|
|
+ $res = Trog::Routes::HTML::guest_reprovision_log( { user => 'admin', user_acls => ['admin'], tpsgi => $tpsgi, guest => 'never.test.test' } );
|
|
|
is( $res->[0], 404, 'and a guest with no log is a 404 rather than an empty page' );
|
|
|
};
|
|
|
|