# frozen_string_literal: true require 'json' require 'optimist' require 'semantic_logger' require_relative 'route_gatherer' require_relative 'version' module OpenVPNConfigurator class CLI include SemanticLogger::Loggable AWS_IP_RANGES_URL = 'https://ip-ranges.amazonaws.com/ip-ranges.json'.freeze def initialize setup_logger end # Expects to be invoked with , def invoke(arguments) options = parse_arguments arguments.dup logger.debug "Beginning CLI invocation run", options: options RouteGatherer.new.extend_template options end private def parse_arguments(original_arguments) arguments = original_arguments.dup logger.trace "Beginning command-line argument parsing", arguments: arguments options = Optimist.options(arguments) do synopsis 'Fetches IP block information from AWS and generates an OpenVPN configuration file' version "openvpn_configurator #{VERSION}" banner self.version banner self.synopsis banner "Usage: #{$0} [options] " banner 'Dynamic route collection options' opt :client, "Run in client mode (directly assign routes instead of pushing them)", type: :boolean, default: false opt :route_v4_aws_region, "Add IPv4 routes for an AWS region (like 'us-west-2')", type: :string, multi: true opt :route_v4_dns, 'Add IPv4 routes for A record(s) returned by the specified DNS query', type: :string, multi: true banner 'Actions' opt :restart_systemd, 'Restart the specified systemd service when the generated configuration changes (including the first time we run)', type: :string, multi: true end if arguments.length != 2 Optimist.die 'Must specify input and output file paths', -2 end options[:input_path] = arguments[0] options[:output_path] = arguments[1] options end def setup_logger # Reset the logger so we can reconfigure it if it was configured before. ::SemanticLogger.flush ::SemanticLogger.close unless ::SemanticLogger.appenders.empty? # Do setup ::SemanticLogger.application = 'openvpn-configurator' ::SemanticLogger.default_level = ENV.fetch('LOG_LEVEL', 'info').downcase.to_sym # Don't colorize output in lambda contexts formatter_options = ENV.has_key?('AWS_EXECUTION_ENV') ? {} : { formatter: :color } if ENV.has_key?('LOG_FILE_PATH') && ENV['LOG_FILE_PATH'] != '-' puts "INFO: Logging to file at #{ENV['LOG_FILE_PATH'].inspect}." ::SemanticLogger.add_appender file_name: ENV['LOG_FILE_PATH'], **formatter_options end if ENV['LOG_FILE_PATH'] == '-' || $stdout.tty? || ENV['LOG_TO_STDOUT'] == 'true' puts "INFO: Logging to stdout." ::SemanticLogger.add_appender io: $stdout, **formatter_options else puts "INFO: stdout is not a TTY, and LOG_TO_STDOUT is not true. No logs will be sent to stdout." end if ENV.has_key? 'GRAYLOG_URL' puts "INFO: Logging to Graylog at #{ENV['GRAYLOG_URL'].inspect}." ::SemanticLogger.add_appender appender: :graylog, url: ENV['GRAYLOG_URL'] end if ENV.has_key? 'STATSD_URL' logger.info "Sending metrics to Statsd at #{ENV['STATSD_URL'].inspect}." subscriber = ::SemanticLogger::Metrics::Statsd.new url: ENV['STATSD_URL'] ::SemanticLogger.on_metric subscriber end end end end