Footprintless

 view release on metacpan or  search on metacpan

lib/Footprintless.pm  view on Meta::CPAN


            my @config_dirs = ();
            if ( $options{config_dirs} ) {
                @config_dirs =
                    ref( $options{config_dirs} ) eq 'ARRAY'
                    ? @{ $options{config_dirs} }
                    : ( $options{config_dirs} );
            }
            elsif ( $ENV{FPL_CONFIG_DIRS} ) {
                @config_dirs = _split_dirs( $ENV{FPL_CONFIG_DIRS} );
            }
            else {
                my $default = File::Spec->catdir( $fpl_home, 'config' );
                if ( -d $default ) {
                    @config_dirs = ($default);
                }
            }

            my @config_options = ();
            if ( $options{config_properties} ) {
                push( @config_options, properties_file => $options{config_properties} );
            }
            elsif ( $ENV{FPL_CONFIG_PROPS} ) {
                my @properties = _split_dirs( $ENV{FPL_CONFIG_PROPS} );
                push( @config_options, properties_file => \@properties );
            }
            else {
                my $default = File::Spec->catdir( $fpl_home, 'properties.pl' );
                if ( -f $default ) {
                    push( @config_options, properties_file => $default );
                }
            }

            $logger->tracef(
                "constructing entities with\n\tconfig_dirs: %s\n\tconfig_options: %s)",
                \@config_dirs, {@config_options} );
            $entities = Config::Entities->new( @config_dirs, {@config_options} );
        }

        $self->{factory} = factory($entities);
    }

    return $self;
}

sub localhost {
    my ( $self, @args ) = @_;
    $self->{factory}->localhost(@args);
}

sub log {
    my ( $self, @args ) = @_;
    $self->{factory}->log(@args);
}

sub plugins {
    my ($self) = @_;
    $self->{factory}->plugins();
}

sub overlay {
    my ( $self, @args ) = @_;
    $self->{factory}->overlay(@args);
}

sub resource_manager {
    my ( $self, @args ) = @_;
    $self->{factory}->resource_manager(@args);
}

sub service {
    my ( $self, @args ) = @_;
    $self->{factory}->service(@args);
}

sub tunnel {
    my ( $self, @args ) = @_;
    $self->{factory}->tunnel(@args);
}

sub _split_dirs {
    my ($dirs_string) = @_;

    my @dirs = ();
    my $separator = ( $^O eq 'MSWin32' ) ? ';' : ':';
    foreach my $dir ( split( /$separator/, $dirs_string ) ) {
        $dir =~ s/^\s+//;
        $dir =~ s/\s+$//;
        push( @dirs, $dir );
    }

    return @dirs;
}

1;

__END__

=pod

=head1 NAME

Footprintless - A utility for managing systems with minimal installs

=head1 VERSION

version 1.29

=head1 SYNOPSIS

    use Footprintless;

    my $footprintless = Footprintless->new();

    # Deploy initialize, start, and follow the log of the foo
    $footprintless->overlay('dev.foo.overlay')->initialize();
    $footprintless->service('dev.foo.service')->start();
    $footprintless->log('dev.foo.logs.app')->follow();

=head1 DESCRIPTION

Footprintless is an automation framework with an application frontend for
managing diverse software stacks in a consistent fashion.  It provides a
minimally invasive approach to configuration management.  At its core, 
L<Config::Entities> are used to define the whole
L<system|https://en.wikipedia.org/wiki/System>.  Once defined, the
entities are used by all of the Footprintless modules to decouple the 
environment from the action.  The environment is defined by the 
entities used to create 
L<command options|Footprintless::CommandOptionsFactory>.  Specifically:

    hostname
    ssh
    sudo_username
    username

Each module will have its own entities structure, see them for more 
details.

=head1 ENTITIES

An example system my consist of multiple environments, each defined
in their own file:

    ./fooptintless
                  /entities
                           /foo
                               /dev.pm
                               /qa.pm
                               /prod.pm

Each one of them would likely be rather similar, perhaps a variation of:

    return {
        app => {
            deployment => {
                'Config::Entities::inherit' => ['hostname', 'sudo_username'],
                clean => [
                    '/opt/foo/tomcat/conf/Catalina/localhost/',
                    '/opt/foo/tomcat/temp/',
                    '/opt/foo/tomcat/webapps/',
                    '/opt/foo/tomcat/work/'
                ],
                resources => {
                    bar => 'com.pastdev:bar:war:1.0',
                    baz => 'com.pastdev:baz:war:1.0'
                },
                to_dir => '/opt/foo/tomcat/webapps'
            },
            hostname => 'app.pastdev.com',
            logs => {
                catalina => '/opt/foo/tomcat/logs/catalina.out'
            },
            overlay => {
                'Config::Entities::inherit' => ['hostname', 'sudo_username'],
                base_dir => '/home/me/git/foo/base',
                clean => [
                    '/opt/foo/tomcat/'
                ],
                deployment_coordinate => 'foo.dev.app.deployment',
                key => 'T',
                os => 'linux',
                resolver_coordinate => 'foo.dev',
                template_dir => '/home/me/git/foo/template',
                to_dir => '/opt/foo/tomcat'
            },
            sudo_username => 'tomcat',
            tomcat => {
                'Config::Entities::inherit' => ['hostname', 'sudo_username'],
                catalina_base => '/opt/foo/tomcat',
                http => {
                    port => 20080
                },
                service => {
                    'Config::Entities::inherit' => ['hostname', 'sudo_username'],
                    action => {
                        'kill' => { command_args => 'stop -force' },
                        'status' => { use_pid => 1 }
                    },
                    command => '/opt/foo/tomcat/bin/catalina.sh',
                    pid_file => '/opt/foo/tomcat/bin/.catalina.pid',
                },
                shutdown => {
                    port => 20005,
                    password => $properties->{'foo.dev.app.tomcat.shutdown.password'},
                },
                trust_store => {
                    'Config::Entities::inherit' => ['hostname', 'sudo_username'],
                    file => '/opt/foo/tomcat/certs/truststore.jks',
                    include_java_home_cacerts => 1,
                    password => $properties->{'foo.dev.app.tomcat.trust_store.password'},
                }
            }
        }
        web => {
            hostname => 'web.pastdev.com',
            logs => {
                error => '/var/log/httpd/error_log',
                access => '/var/log/httpd/access_log'
            }
            sudo_username => 'apache'
        }
    }

Then when you decide to perform an action, the environment is just part
of the coordinate:

    fpl log foo.dev.app.tomcat.logs.catalina follow

    fpl service foo.qa.app.tomcat.service status

    fpl deployment foo.prod.app.deployment deploy --clean

If using the framework instead, the story is the same:

lib/Footprintless.pm  view on Meta::CPAN

operate on the deployment at C<$coordinate>.  Supported options are

=over 4

=item command_options_factory

A C<command_options_factory> to use instead of that which is supplied by
this footprintless instance.

=item command_runner

A C<command_runner> to use instead of that which is supplied by
this footprintless instance.

=item localhost

A C<localhost> to use instead of that which is supplied by
this footprintless instance.

=item resource_manager

A C<resource_manager> to use instead of that which is supplied by
this footprintless instance.

=back

=head2 entities()

Returns the L<Config::Entities> that were resolved by this footprintless
instance.

=head2 localhost()

Returns the L<localhost|Footprintless::Localhost> resolver used by 
this instance.

=head2 log($coordinate, %options)

Returns a new instance of L<Footprintless::Log> preconfigured to
operate on the log at C<$coordinate>.  Supported options are

=over 4

=item command_options_factory

A C<command_options_factory> to use instead of that which is supplied by
this footprintless instance.

=item command_runner

A C<command_runner> to use instead of that which is supplied by
this footprintless instance.

=item localhost

A C<localhost> to use instead of that which is supplied by
this footprintless instance.

=back

=head2 overlay($coordinate, %options)

Returns a new instance of L<Footprintless::Overlay> preconfigured to
operate on the overlay at C<$coordinate>.  Supported options are

=over 4

=item command_options_factory

A C<command_options_factory> to use instead of that which is supplied by
this footprintless instance.

=item command_runner

A C<command_runner> to use instead of that which is supplied by
this footprintless instance.

=item localhost

A C<localhost> to use instead of that which is supplied by
this footprintless instance.

=item resource_manager

A C<resource_manager> to use instead of that which is supplied by
this footprintless instance.

=back

=head2 plugins()

Returns the registered plugins for this instance.

=head2 resource_manager()

Returns the L<resource_manager|Footprintless::ResourceManager> used by 
this instance.

=head2 service($coordinate, %options)

Returns a new instance of L<Footprintless::Service> preconfigured to
operate on the service at C<$coordinate>.  Supported options are

=over 4

=item command_options_factory

A C<command_options_factory> to use instead of that which is supplied by
this footprintless instance.

=item command_runner

A C<command_runner> to use instead of that which is supplied by
this footprintless instance.

=item localhost

A C<localhost> to use instead of that which is supplied by
this footprintless instance.

=back

=head2 tunnel($coordinate, %options)



( run in 1.905 second using v1.01-cache-2.11-cpan-7fcb06a456a )