File Coverage

blib/lib/omnitool/installer.pm
Criterion Covered Total %
statement 26 200 13.0
branch 0 68 0.0
condition 0 18 0.0
subroutine 9 16 56.2
pod 0 7 0.0
total 35 309 11.3


line stmt bran cond sub pod time code
1             package omnitool::installer;
2              
3 1     1   794 use 5.022001;
  1         4  
4 1     1   6 use strict;
  1         2  
  1         19  
5 1     1   5 use warnings;
  1         1  
  1         39  
6              
7             our $VERSION = "1.0.13";
8              
9             # for reading in configs
10 1     1   1661 use File::Slurp;
  1         24572  
  1         70  
11 1     1   1698 use IO::Prompter;
  1         37223  
  1         8  
12 1     1   824 use Getopt::Long;
  1         10418  
  1         5  
13              
14             # for creating config files
15 1     1   731 use Template;
  1         19309  
  1         34  
16              
17             # for building databases
18 1     1   2065 use DBI;
  1         19184  
  1         67  
19              
20             # for getting default hostname/domain name
21 1     1   550 use Net::Domain qw( hostfqdn domainname );
  1         8841  
  1         2673  
22              
23             # create myself and try to grab arguments
24             sub new {
25 0     0 0   my $class = shift;
26              
27             # our variables
28 0           my ($self, $default_text, $hostname, $domainname, $options_map, $option_keys, $options, $options_file, $line, $name, $value, $option_key, $my_git_repo);
29              
30             # my default hostname and domain name
31 0           $hostname = hostfqdn();
32 0           $domainname = domainname();
33              
34             # where OmniTool lives
35 0           $my_git_repo = 'https://github.com/ericschernoff/omnitool';
36              
37             # we need a map of what our options mean and their defaults
38             # the default will be the second item in the array, if there is a default
39             $options_map = {
40             'config-file' => ['Full path to a file name which will include some/all of the config parameters for this installer, one name=value pairs, one per line. Provided args will override.'],
41             'save-config-file' => ['If you wish to save a file with config parameters, provide a full path to the new file.'],
42             'save-config-file-only' => ['Will save file with config parameters and exit without attempting to install; provide a full path to the new file.'],
43             'othome' => ['The root directory for OmniTool, e.g. /usr/local/omnitool','/opt/omnitool'],
44             'database-server' => ['Hostname or IP address of primary MySQL database server','127.0.0.1'],
45             'db-username' => ['Username for connecting to MySQL; value must be provided'],
46             'db-password' => ['Password for connecting to MySQL; value must be provided'],
47             'init-vector' => ['Init vector for MySQL encryption; value longer than 10 characters must be provided'],
48             'salt-phrase' => ['Salt phrase for MySQL encryption; value longer than 10 characters must be provided'],
49             'ot-cookie-domain' => ['The domain name for the authentication cookie',$domainname],
50             'ot-primary-hostname' => ['The full hostname for the main Web URI for this system',$hostname],
51             'omnitool-admin' => ['The email address of the responsible party(ies) for this OmniTool system',$ENV{USER}.'@'.$domainname],
52 0           'os-username' => ['The OS username who will run and own all OmniTool processes and resources',$ENV{USER}],
53             'admin-ui-password' => [qq{The password for the 'omnitool_admin' user in the OT Admin Web UI; value must be provided}],
54             'source_git_repo' => [qq{The source repo for OmniTool; change from default only if you have your own trusted fork.}, $my_git_repo],
55             };
56 0           $option_keys = [
57             'config-file','save-config-file','save-config-file-only',
58             'othome','database-server','db-username','db-password',
59             'init-vector','salt-phrase',
60             'omnitool-admin','os-username','admin-ui-password',
61             'ot-cookie-domain','ot-primary-hostname','source_git_repo'
62             ];
63              
64             # what arguments did they send?
65 0           $options = {};
66 0           GetOptions ($options, qw(-help+
67             -config-file=s -save-config-file=s -save-config-file-only=s
68             -othome=s -database-server=s
69             -db-username=s -db-password=s init-vector=s -salt-phrase=s -ot-cookie-domain=s
70             -admin-ui-password=s -ot-primary-hostname=s -omnitool-admin=s -os-username=s
71             -source_git_repo=s)
72             );
73              
74             # do they just want to see the help screen?
75 0 0         if ($$options{help}) {
76 0           $self = bless {
77             'options' => $options,
78             'options_map' => $options_map,
79             'option_keys' => $option_keys,
80             }, $class;
81 0           $self->print_help_text();
82             }
83              
84             # if they sent a file that exists, read it to get any options now already sent
85 0 0 0       if ($$options{'config-file'} && (-e $$options{'config-file'})) {
86 0           $options_file = read_file($$options{'config-file'});
87 0           foreach $line (split /\n/, $options_file) {
88 0           ($name,$value) = split /\s?\=\s?/, $line;
89 0 0         next if $$options{$name}; # skip if already filled
90 0           $$options{$name} = $value
91             }
92             }
93              
94             # now we need to validate what we have so far, and prompt for what we do not have
95 0           foreach $option_key (@$option_keys) {
96 0 0         next if $option_key =~ /config-file/; # not for the config files
97              
98             # if we do not have a value for this option, prompt for it
99 0 0         if (!$$options{$option_key}) {
100             # does it have a default?
101 0 0         if ($$options_map{$option_key}[1]) {
102 0           $default_text = ' [Default: '.$$options_map{$option_key}[1].']: ';
103             } else { # no default
104 0           $default_text = ' [No Default] : ';
105             }
106              
107             # password mode?
108 0 0         if ($option_key =~ /password/i) {
109 0           $$options{$option_key} = prompt $$options_map{$option_key}[0].$default_text, -v, -echo=>'*';
110             } else { # OK to show
111 0           $$options{$option_key} = prompt $$options_map{$option_key}[0].$default_text, -v;
112             }
113              
114             # if it was not provided, take any calculated default
115 0 0         $$options{$option_key} = $$options_map{$option_key}[1] if !length($$options{$option_key});
116              
117             # if it is required and either does not exist or is not long enough, then die() here.
118 0 0 0       if (!length($$options{$option_key}) && ($$options_map{$option_key}[0] =~ /must be provided/ || $option_key eq 'source_git_repo')) {
    0 0        
      0        
119 0           die(qq{ERROR: You must provide a value for the '$option_key' option. Please run 'omnitool-installer --help' for details.}."\n");
120             } elsif (length($$options{$option_key}) < 10 && $$options_map{$option_key}[0] =~ /longer than 10 characters/) {
121 0           die(qq{ERROR: Value for '$option_key' option must be 10 characters or greater. Please run 'omnitool-installer --help' for details.}."\n");
122             }
123              
124             }
125             }
126              
127             # set up the object with all the options data
128 0           $self = bless {
129             'options' => $options,
130             'options_map' => $options_map,
131             'option_keys' => $option_keys,
132             }, $class;
133              
134             # do they want to save these configs back out (and potentially exit)?
135 0 0 0       if ($self->{options}{'save-config-file'} || $self->{options}{'save-config-file-only'}) {
136 0           $self->save_config_file();
137             }
138              
139             # if we are still alive, send it back
140 0           return $self;
141             }
142              
143             # method to undertake all the installation tasks
144             sub do_the_installation {
145 0     0 0   my $self = shift;
146              
147 0           my (@sub_directories, $config_file, $sub_directory, $the_sub_directory, $belt, $db_info, $distribution_directory, $htdocs_source, $htdocs_link, $omnitool_pm_source, $omnitool_pm_link, @ot_code_pieces, $ot_code_piece, $ot_code_source, $ot_code_link, @web_urls, $next_steps,$next_steps_file);
148              
149 0           print "\n\nATTEMPTING INSTALLATION TASKS:\n\n";
150              
151             # here are the sub-directories we need
152 0           @sub_directories = qw(
153             code code/omnitool code/omnitool/applications
154             configs configs/ssl_cert
155             files hash_cache
156             htdocs log log/archive
157             tmp tmp/docs tmp/email_incoming tmp/pids
158             );
159              
160             # start with the home directory
161 0 0         if (!(-d $self->{options}{othome})) {
162 0           mkdir($self->{options}{othome}, 0755);
163 0           print "Created OmniTool root directory at ".$self->{options}{othome}."\n";
164             } else {
165 0           print "OmniTool root directory already exists at ".$self->{options}{othome}."\n";
166             }
167              
168             # no go through the sub directories
169 0           foreach $sub_directory (@sub_directories) {
170 0           $the_sub_directory = $self->{options}{othome}.'/'.$sub_directory;
171 0 0         if (!(-d $the_sub_directory)) {
172 0           mkdir($the_sub_directory, 0755);
173 0           print "Created $the_sub_directory\n";
174             } else {
175 0           print "Skipped $the_sub_directory - already exists\n";
176             }
177             }
178              
179             # our distribution directory will be here:
180 0           $distribution_directory = $self->{options}{othome}.'/distribution';
181              
182             # now pull down the code
183 0 0         if (-d $distribution_directory.'/omnitool') { # already there, need to do a 'git pull'
184 0           chdir $distribution_directory;
185 0           system('git','pull');
186 0           print "Latest OmniTool code repo *pulled* into $distribution_directory\n";
187              
188             } else { # need to do a clone
189 0           system('git','clone',$self->{options}{source_git_repo},$distribution_directory);
190 0           print "Latest OmniTool code repo *cloned* into $distribution_directory\n";
191             }
192              
193             # link distribution/htdocs to OTHOME/htdocs/omnitool
194 0           $htdocs_source = $distribution_directory.'/htdocs';
195 0           $htdocs_link = $self->{options}{othome}.'/htdocs/omnitool';
196 0 0         if (!(-l $htdocs_link)) {
197 0           symlink $htdocs_source, $htdocs_link;
198 0           print "Linked static (HTML/JS/CSS/Images) collateral to $htdocs_link.\n";
199             } else {
200 0           print "Skipped link to static (HTML/JS/CSS/Images) collateral to $htdocs_link; symlink already exists.\n";
201             }
202              
203             # now link to the code, but make it possible for them to write their own applications under $OTPERL/applications
204              
205             # first: omnitool.pm
206 0           $omnitool_pm_source = $distribution_directory.'/omnitool.pm';
207 0           $omnitool_pm_link = $self->{options}{othome}.'/code/omnitool.pm';
208 0 0         if (!(-l $omnitool_pm_link)) {
209 0           symlink $omnitool_pm_source, $omnitool_pm_link;
210 0           print "Linked omnitool.pm to $omnitool_pm_link.\n";
211             } else {
212 0           print "Skipped link of omnitool.pm to $omnitool_pm_link; symlink already exists.\n";
213             }
214              
215             # now the bits under the actual directory
216 0           @ot_code_pieces = qw(
217             common dispatcher.pm main.psgi omniclass omniclass.pm scripts
218             static_files tool tool.pm
219             applications/otadmin applications/sample_apps
220             );
221 0           foreach $ot_code_piece (@ot_code_pieces) {
222 0           $ot_code_source = $distribution_directory.'/omnitool/'.$ot_code_piece;
223 0           $ot_code_link = $self->{options}{othome}.'/code/omnitool/'.$ot_code_piece;
224 0 0         if (!(-l $ot_code_link)) {
225 0           symlink $ot_code_source, $ot_code_link;
226 0           print "Linked $ot_code_source to $ot_code_link.\n";
227             } else {
228 0           print "Skipped link of $ot_code_source to $ot_code_link; symlink already exists.\n";
229             }
230             }
231              
232             # now, let's set up configs/dbinfo.txt
233 0           $db_info = $self->{options}{'db-username'}."\n".$self->{options}{'db-password'};
234 0           $self->stash_some_text($db_info, $self->{options}{othome}.'/configs/dbinfo.txt');
235              
236             # now create the configuration files
237 0           foreach $config_file ('bash_aliases.tt','mysql_omnitool.cnf.tt','omnitool.service.tt','omnitool_apache.conf.tt','start_omnitool.bash.tt') {
238 0           $self->create_config_files($config_file);
239             }
240              
241             # symlink over code map
242 0           symlink $self->{options}{othome}.'/distribution/configs/ot6_modules.yml', $self->{options}{othome}.'/configs/ot6_modules.yml';
243              
244             # if the user who will run OT6 is not the same username running this script, run a chown
245 0 0         if ($ENV{USER} ne $self->{options}{'os-username'}) {
246 0           system('chown -R '.$self->{options}{'os-username'}.' '.$self->{options}{othome});
247             }
248              
249             # final step is the database work
250             # we need to log into the database and see if we need to create the 'omnitool' and 'otstatedata' DB's
251             # and then set up their OT6 Admin user
252 0           $self->setup_databases();
253              
254             # what is left for them to do?
255 0           $web_urls[0] = 'https://'.$self->{options}{'ot-primary-hostname'}.'/sample_apps_admin';
256 0           $web_urls[1] = 'https://'.$self->{options}{'ot-primary-hostname'}.'/sample_tools';
257 0           $web_urls[2] = 'https://'.$self->{options}{'ot-primary-hostname'}.'/apps_admin';
258 0           $web_urls[3] = 'https://'.$self->{options}{'ot-primary-hostname'}.'/apps_admin#/tools/view_module_docs';
259 0           $next_steps = qq{
260             OMNITOOL INSTALLATION IS COMPLETE.
261              
262             Next Steps:
263             1. Adjust your CLI environment by adding this to ~/.bash_aliases:
264             source $self->{options}{othome}/configs/bash_aliases
265             2. Bring in the Apache config (or adjust Nginix to taste). For Ubuntu:
266             cd /etc/apache2/conf-enabled ; ln -s $self->{options}{othome}/configs/omnitool_apache.conf
267             3. Install SSL certificates in here: $self->{options}{othome}/configs/ssl_cert
268             - Self-signing cert info: https://httpd.apache.org/docs/2.4/ssl/ssl_faq.html#selfcert
269             - You will need to edit lines 76-78 in $self->{options}{othome}/configs/omnitool_apache.conf
270             4. Restart Apache: sudo systemctl restart apache2
271             5. Review/tweak and install the special MySQL Config File. For Ubuntu:
272             cd /etc/mysql/mysql.conf.d ; sudo cp /opt/omnitool/configs/mysql_omnitool.cnf ./
273             \$EDITOR mysql_omnitool.cnf
274             sudo systemctl restart mysql
275             6. Reviw/tweak the script to start the Plack Service, especially lines 24-42:
276             \$EDITOR /opt/omnitool/configs/start_omnitool.bash
277             # Note the 'RECAPTCHA' vars if you want to use Google's ReCaptcha service.
278             7. Start the Plack Service:
279             sudo /opt/omnitool/configs/start_omnitool.bash start
280             (Look at the omnitool.service SystemD script under /opt/omnitool/configs/ as well.)
281             8. Check out the sample apps:
282             Admin: $web_urls[0]
283             User-Facing: $web_urls[1]
284             9. Read some Perl docs: $web_urls[3]
285             10. Get Started on Your Apps: $web_urls[2]
286              
287             ** The username for the Web URL's in steps 8-10 will be 'omnitool_admin' with the
288             password you gave for the ''admin-ui-password' option. **
289              
290             If you have any questions, please reach out to ericschernoff\@gmail.com .
291             };
292              
293             # save that to their home directory
294 0           $next_steps_file = $self->{options}{othome}.'/configs/omnitool_next_steps.txt';
295 0           write_file($next_steps_file,$next_steps);
296              
297             # output it, telling them where it is
298 0           print $next_steps."\n(A copy of these next steps have been saved to $next_steps_file .\n";
299              
300             }
301              
302             # stripped-down version of text-stashing
303             sub stash_some_text {
304 0     0 0   my $self = shift;
305              
306 0           my ($text_to_stash,$file_location) = @_;
307              
308             # garble it up
309 0           my $obfuscated = unpack "h*", $text_to_stash;
310             # get this out like:
311             # $obfuscated = read_file($file_location);
312             # my $stashed_text = pack "h*", $obfuscated;
313             # print $stashed_text."\n";
314             # This is 0.0000001% of what pack() can do, please see: http://perldoc.perl.org/functions/pack.html
315              
316             # stash it out
317 0           write_file( $file_location, $obfuscated);
318              
319 0           return 1;
320             }
321              
322             # method to create new config files from my templates
323             sub create_config_files {
324 0     0 0   my $self = shift;
325              
326             # the name of the config file template we are going to create
327 0           my ($config_filename) = @_;
328             # return if blank or non-existent
329 0 0 0       return if !$config_filename || !(-e $self->{options}{othome}.'/distribution/configs/'.$config_filename);
330              
331 0           my ($destination_file, $output, $tt, $key, $new_key);
332              
333             # where is it going?
334 0           $destination_file = $self->{options}{othome}.'/configs/'.$config_filename;
335 0           $destination_file =~ s/.tt$//;
336              
337             # if it exists, abort
338 0 0         if (-e $destination_file) {
339 0           print "SKIPPED: Can not overwrite config file: $destination_file ; please delete and re-attempt or adjust by hand.\n";
340 0           return;
341             }
342              
343             # i hate dashes, but felt like they were standard in the args
344 0           foreach $key ('database-server','omnitool-admin','os-username','init-vector','salt-phrase','ot-cookie-domain','ot-primary-hostname') {
345 0           ($new_key = $key) =~ s/-/_/g;
346 0           $self->{options}{$new_key} = $self->{options}{$key};
347             }
348              
349             # prepare template toolkit
350 0           $output = ''; # where the text shall go
351             $tt = Template->new({
352             ENCODING => 'utf8',
353 0           INCLUDE_PATH => $self->{options}{othome}.'/distribution/configs/',
354             OUTPUT => \$output,
355             });
356             # process the template
357 0           $tt->process($config_filename, $self, $output, {binmode => ':encoding(utf8)'});
358              
359             # save the new file under OTHOME/configs
360 0           write_file($destination_file, $output);
361              
362             # if it's start_omnitool.bash.tt, make it executable
363 0 0         if ($config_filename eq 'start_omnitool.bash.tt') {
364 0           chmod 0744, $destination_file;
365             }
366              
367             # symlink over code map
368 0           symlink $self->{options}{othome}.'/distribution/configs/ot6_modules.yml', $self->{options}{othome}.'/configs/ot6_modules.yml';
369              
370             # report success
371 0           print "Created config file $destination_file ; please verify and adjust.\n";
372 0           return;
373             }
374              
375             # method to set up the 'omnitool' and 'otstatedata' databases
376             sub setup_databases {
377 0     0 0   my $self = shift;
378              
379 0           my ($dsn, $dbh, $db_name, $sth, $exists, $safe_to_modify);
380              
381             # try to make the connection
382 0           $dsn = qq{DBI:mysql:database=information_schema;host=}.$self->{options}{'database-server'}.qq{;port=3306};
383 0           $dbh = DBI->connect($dsn, $self->{options}{'db-username'}, $self->{options}{'db-password'},{ PrintError => 1, RaiseError=>1, mysql_enable_utf8=>8 });
384 0           $dbh->{LongReadLen} = 1000000;
385              
386             # check to see if it has our databases
387 0           foreach $db_name ('omnitool','otstatedata','omnitool_applications','omnitool_samples','sample_tools') {
388 0           $sth = $dbh->prepare(qq{select CATALOG_NAME from SCHEMATA where SCHEMA_NAME='$db_name'});
389 0 0         $sth->execute or print $dbh->errstr."\n";
390 0           ($exists) = $sth->fetchrow_array;
391 0 0         if ($exists) { # if it exists, skip it
392 0           print "SKIPPED: $db_name already exists and was not be overwritten.\n";
393             } else { # otherwise, load it in
394 0           $sth = $dbh->prepare(qq{create database $db_name});
395 0 0         $sth->execute or print $dbh->errstr."\n";
396 0           system('mysql -u'.$self->{options}{'db-username'}.' -p'.$self->{options}{'db-password'}.' -h'.$self->{options}{'database-server'}.' '.$db_name.' < '.$self->{options}{othome}.'/distribution/schema/'.$db_name.'.sql');
397 0           print "Created $db_name from included schema.\n";
398             # so we know we can update the databases below with out install tweaks
399 0           $$safe_to_modify{$db_name} = 1;
400             }
401             }
402              
403             # start tweaking the omnitool(_*) DB's
404              
405 0 0         if ($$safe_to_modify{omnitool}) { # can modify core omnitool admin
406             # fix the password for the 'omnitool_admin' user in all three databases
407 0           foreach $db_name ('omnitool','omnitool_applications','omnitool_samples') {
408 0           $sth = $dbh->prepare('update '.$db_name.qq{.omnitool_users set password=sha2(?,224) where username='omnitool_admin'});
409 0 0         $sth->execute($self->{options}{'admin-ui-password'}) or print $dbh->errstr."\n";
410             }
411              
412 0           print "Set Password for 'omnitool_admin' user in the OmniTool Admin Web UI.\n";
413              
414             # fix the name and hostname of the Apps for their domain
415 0           $sth = $dbh->prepare(qq{update omnitool.instances set name=?, hostname=? where code='10'});
416 0 0         $sth->execute('Admin for '.ucfirst($self->{options}{'ot-cookie-domain'}), 'apps-admin.'.$self->{options}{'ot-cookie-domain'}) or print $dbh->errstr."\n";
417              
418             # fix the name and hostname of the Sample Apps
419 0           $sth = $dbh->prepare(qq{update omnitool.instances set hostname=? where code='9'});
420 0 0         $sth->execute('sample-apps-admin.'.$self->{options}{'ot-cookie-domain'}) or print $dbh->errstr."\n";
421              
422 0           print "Updated Name, Hostname for Custom Applications Admin UI.\n";
423              
424             } else {
425              
426 0           print "SKIPPED: Could not modify 'omnitool_admin' password; Core 'omnitool' database already exists.\n";
427              
428             }
429              
430             # Update all database server records
431 0           foreach $db_name ('omnitool','omnitool_applications','omnitool_samples') {
432 0 0         if ($$safe_to_modify{$db_name}) {
433 0           $sth = $dbh->prepare('update '.$db_name.qq{.database_servers set hostname=?});
434 0 0         $sth->execute($self->{options}{'database-server'}) or print $dbh->errstr."\n";
435              
436 0           print "Set database server hostname for $db_name.\n";
437              
438             } else {
439 0           print "SKIPPED: Could not set database server hostname for $db_name; that database already exists.\n";
440             }
441             }
442              
443             }
444              
445             # method to save out the config file if they sent the right arguments
446             sub save_config_file {
447 0     0 0   my $self = shift;
448              
449 0           my ($option_key, $options_config);
450              
451             # just need a set of name=value pairs, one per line
452 0           foreach $option_key (@{ $self->{option_keys} }) {
  0            
453 0 0         next if $option_key =~ /config-file/; # not for the config files
454 0           $options_config .= $option_key.'='.$self->{options}{$option_key}."\n";
455             }
456              
457             # take off the last character
458 0           chomp($options_config);
459              
460             # just save?
461 0 0         if ($self->{options}{'save-config-file'}) {
    0          
462              
463 0           write_file($self->{options}{'save-config-file'}, $options_config);
464              
465 0           print "\n\nConfig options file saved to ".$self->{options}{'save-config-file'}."\n\n";
466              
467             # or save an exit
468             } elsif ($self->{options}{'save-config-file-only'}) {
469              
470 0           write_file($self->{options}{'save-config-file-only'}, $options_config);
471              
472 0           print "\n\nConfig options file saved to ".$self->{options}{'save-config-file-only'}." and no further action taken.\n\n";
473 0           exit;
474             }
475             }
476              
477             # method to print a help screen, based on map above
478             sub print_help_text {
479 0     0 0   my $self = shift;
480              
481             # start with intro
482 0           print qq{
483             OmniTool Installer: Retrieves and installs the OmniTool Web Framework onto this system.
484              
485             Usage: omnitool_installer [OPTIONS]
486             Must provide either a config_file or all options, where options are:
487              
488             Git Repo for OmniTool: https://github.com/ericschernoff/omnitool
489              
490             OmniTool Website: http://www.omnitool.org
491              
492             Requires Ubuntu 16.04+ (or distro based on 16.04), as well as Perl 5.22+ and Git.
493             Also requires MySQL 5.7+ or MariaDB 10.3+ here or close by, and it's no fun without
494             Apache installed.
495              
496             Before running, please install the following packages:
497              
498             zlib1g-dev libssl-dev install build-essential cpanminus perl-doc
499             mysql-server libmysqlclient-dev apache2
500              
501             Then, you will need to enable a few Apache modules:
502              
503             a2enmod proxy ssl headers proxy_http rewrite
504              
505             };
506 0           foreach my $option_key (@{ $self->{option_keys} }) {
  0            
507 0           print '--'.$option_key.' ';
508 0 0         if ($self->{options_map}{$option_key}[1]) {
509 0           print $self->{options_map}{$option_key}[0].': [Default: '.$self->{options_map}{$option_key}[1].']';
510             } else {
511 0           print $self->{options_map}{$option_key}[0].': [No Default]';
512             }
513 0           print "\n\n";
514             }
515              
516             # done here
517 0           exit;
518             }
519              
520             1;
521              
522             __END__
523              
524             =encoding utf-8
525              
526             =head1 NAME
527              
528             omnitool::installer - Install the OmniTool Web Application Framework
529              
530             Provides the 'omnitool_installer' script to install OmniTool on your system.
531              
532             =head1 END-OF-LIFE / DEPRECATION
533              
534             This system is no longer under active development. OmniTool should not be used for any new projects.
535              
536             This repo contains some interesting ideas and perhaps a few solutions, so this repo will remain online for archive purposes. If you are interested in taking over this project, please let me know.
537              
538             =head1 SYNOPSIS
539              
540             # To provide installation details interactively then install:
541             omnitool_installer
542              
543             # Safer approach: provide the installation details interactively and save config file:
544             omnitool_installer --save-config-file-only=/some/path/ot_install.config
545             # then run
546             omnitool_installer --config-file=/some/path/ot_install.config
547              
548             # Be sure to delete/protect ot_install.config
549              
550             # To see help and exit:
551             omnitool_installer --help
552              
553             =head1 DESCRIPTION
554              
555             OmniTool allows you to build web application suites very quickly and with minimal code. It is
556             designed to simplify and speed up the development process, reducing code requirements to only
557             the specific features and logic for the target application. The resulting applications are
558             mobile-responsive and API-enabled with no extra work by the developers.
559              
560             For lots more information on how this works, including demos, examples, and lots of documentation,
561             please visit L<http://www.omnitool.org/>
562              
563             The GitHub Repo for OmniTool is L<https://github.com/ericschernoff/omnitool>
564              
565             =head2 PREREQUISITES
566              
567             OmniTool has been developed and tested with the following base components:
568              
569             =over
570              
571             =item - Ubuntu 16.04 Server
572              
573             =item - Perl 5.22
574              
575             =item - Git 2.10
576              
577             =item - MySQL 5.7 or MariaDB 10.3 (at least the client libraries if separate DB server)
578              
579             =item - Apache 2.4
580              
581             =back
582              
583             You can very likely make it work on FreeBSD 10.1+ or a recent release of RHEL, Fedora, or CentOS. I am not able
584             to provide detailed instructions on each of these -- volunteers would be very welcome!
585              
586             Prior to installation, the following packages will need to be installed via 'sudo apt install':
587              
588             =over
589              
590             =item - build-essential
591              
592             =item - zlib1g-dev
593              
594             =item - libssl-dev
595              
596             =item - cpanminus
597              
598             =item - perl-doc
599              
600             =item - mysql-server
601              
602             =item - libmysqlclient-dev
603              
604             =item - apache2
605              
606             =back
607              
608             Then, you will need to enable a few Apache modules:
609              
610             =over
611              
612             sudo a2enmod proxy ssl headers proxy_http rewrite
613              
614             =back
615              
616             Again, these are Ubuntu 16.04 commands. I am quite sure you can make this work with the other BSD, Linux
617             flavors, as well as with Nginix instead of Apache if you prefer.
618              
619             =head2 ACKNOWLEDGEMENTS
620              
621             I am very appreciative to my employer, Cisco Systems, Inc., for allowing this software to be
622             released to the community as open source. (IP Central ID: 153330984).
623              
624             I am also grateful to Mohsen Hosseini for allowing me to include his most excellent Ace
625             Admin as part of this software.
626              
627             =head1 LICENSE
628              
629             MIT License
630              
631             Copyright (c) 2017 Eric Chernoff
632              
633             Permission is hereby granted, free of charge, to any person obtaining a copy
634             of this software and associated documentation files (the "Software"), to deal
635             in the Software without restriction, including without limitation the rights
636             to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
637             copies of the Software, and to permit persons to whom the Software is
638             furnished to do so, subject to the following conditions:
639              
640             The above copyright notice and this permission notice shall be included in all
641             copies or substantial portions of the Software.
642              
643             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
644             IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
645             FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
646             AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
647             LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
648             OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
649             SOFTWARE.
650              
651             =head1 AUTHOR
652              
653             Eric Chernoff E<lt>ericschernoff@gmail.comE<gt>
654              
655             =cut
656