prometheus-splash 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -1
- data/README.md +1 -1
- data/config/splash.yml +33 -5
- data/lib/splash/backends.rb +1 -0
- data/lib/splash/cli.rb +2 -1
- data/lib/splash/cli/daemon.rb +41 -1
- data/lib/splash/cli/transfers.rb +206 -0
- data/lib/splash/cli/webadmin.rb +3 -3
- data/lib/splash/config.rb +44 -30
- data/lib/splash/constants.rb +7 -2
- data/lib/splash/daemon/metrics.rb +6 -6
- data/lib/splash/daemon/orchestrator.rb +76 -36
- data/lib/splash/daemon/orchestrator/grammar.rb +16 -1
- data/lib/splash/dependencies.rb +6 -1
- data/lib/splash/helpers.rb +11 -2
- data/lib/splash/loggers/cli.rb +2 -10
- data/lib/splash/transfers.rb +224 -0
- data/lib/splash/webadmin.rb +3 -3
- data/lib/splash/webadmin/main.rb +1 -0
- data/lib/splash/webadmin/portal/controllers/home.rb +19 -0
- data/lib/splash/webadmin/portal/controllers/proxy.rb +10 -2
- data/lib/splash/webadmin/portal/views/home.slim +50 -5
- data/lib/splash/webadmin/portal/views/proxy.slim +3 -0
- data/prometheus-splash.gemspec +5 -2
- metadata +62 -4
    
        data/lib/splash/constants.rb
    CHANGED
    
    | @@ -7,7 +7,7 @@ module Splash | |
| 7 7 | 
             
              module Constants
         | 
| 8 8 |  | 
| 9 9 | 
             
                # Current splash version
         | 
| 10 | 
            -
                VERSION = "0. | 
| 10 | 
            +
                VERSION = "0.8.0"
         | 
| 11 11 |  | 
| 12 12 | 
             
                # the path to th config file, not overridable by config
         | 
| 13 13 | 
             
                CONFIG_FILE = "/etc/splash.yml"
         | 
| @@ -43,7 +43,10 @@ module Splash | |
| 43 43 | 
             
                LICENSE="BSD-2-Clause"
         | 
| 44 44 |  | 
| 45 45 | 
             
                # the default prometheus pushgateway URL
         | 
| 46 | 
            -
                PROMETHEUS_PUSHGATEWAY_URL = 'http://localhost: | 
| 46 | 
            +
                PROMETHEUS_PUSHGATEWAY_URL = 'http://localhost:9091/'
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                # the default prometheus Alertmanager URL
         | 
| 49 | 
            +
                PROMETHEUS_ALERTMANAGER_URL = 'http://localhost:9092/'
         | 
| 47 50 |  | 
| 48 51 | 
             
                # the default prometheus URL
         | 
| 49 52 | 
             
                PROMETHEUS_URL = "http://localhost:9090/"
         | 
| @@ -84,6 +87,8 @@ module Splash | |
| 84 87 | 
             
                # the default sdterr trace file
         | 
| 85 88 | 
             
                WEBADMIN_STDERR_TRACE="stderr.txt"
         | 
| 86 89 |  | 
| 90 | 
            +
                # default transfer retention for trace
         | 
| 91 | 
            +
                TRANSFER_DEFAULT_RETENTION=1
         | 
| 87 92 |  | 
| 88 93 | 
             
              end
         | 
| 89 94 | 
             
            end
         | 
| @@ -17,8 +17,8 @@ module Splash | |
| 17 17 |  | 
| 18 18 | 
             
                  # metrics manager factory
         | 
| 19 19 | 
             
                  # @return [Splash::Daemon::Metrics::Manager]
         | 
| 20 | 
            -
                  def get_metrics_manager
         | 
| 21 | 
            -
                    return @@manager ||= Manager::new
         | 
| 20 | 
            +
                  def get_metrics_manager(session)
         | 
| 21 | 
            +
                    return @@manager ||= Manager::new(:session => session)
         | 
| 22 22 | 
             
                  end
         | 
| 23 23 |  | 
| 24 24 | 
             
                  # Metrics Manager (collect and sending to Prometheus)
         | 
| @@ -32,7 +32,8 @@ module Splash | |
| 32 32 | 
             
                    attr_reader :monitoring_processes_count
         | 
| 33 33 |  | 
| 34 34 | 
             
                    # Constructor prepare prometheus-client, defined metrics and init attributes
         | 
| 35 | 
            -
                    def initialize
         | 
| 35 | 
            +
                    def initialize(options ={})
         | 
| 36 | 
            +
                      @session = options[:session]
         | 
| 36 37 | 
             
                      @config = get_config
         | 
| 37 38 | 
             
                      @starttime = Time.now
         | 
| 38 39 | 
             
                      @execution_count = 0
         | 
| @@ -75,12 +76,11 @@ module Splash | |
| 75 76 | 
             
                    # @return [Hash] Exiter case ( :service_dependence_missing , :quiet_exit)
         | 
| 76 77 | 
             
                    def notify
         | 
| 77 78 | 
             
                      log = get_logger
         | 
| 78 | 
            -
                      session  = get_session
         | 
| 79 79 | 
             
                      unless verify_service url: @config.prometheus_pushgateway_url then
         | 
| 80 80 | 
             
                        return  { :case => :service_dependence_missing, :more => "Prometheus Notification not send." }
         | 
| 81 81 | 
             
                      end
         | 
| 82 82 |  | 
| 83 | 
            -
                      log. | 
| 83 | 
            +
                      log.ok "Sending Splash self metrics to PushGateway." , @session
         | 
| 84 84 | 
             
                      @metric_uptime.set uptime
         | 
| 85 85 | 
             
                      @metric_execution.set execution_count
         | 
| 86 86 | 
             
                      @metric_logs_monitoring.set monitoring_logs_count
         | 
| @@ -89,7 +89,7 @@ module Splash | |
| 89 89 | 
             
                      hostname = Socket.gethostname
         | 
| 90 90 | 
             
                      url = @config.prometheus_pushgateway_url
         | 
| 91 91 | 
             
                      Prometheus::Client::Push.new('Splash',hostname, url).add(@registry)
         | 
| 92 | 
            -
                      log.debug "Sending to Prometheus PushGateway done.", session
         | 
| 92 | 
            +
                      log.debug "Sending to Prometheus PushGateway done.", @session
         | 
| 93 93 | 
             
                      return {:case => :quiet_exit }
         | 
| 94 94 | 
             
                    end
         | 
| 95 95 |  | 
| @@ -32,20 +32,69 @@ module Splash | |
| 32 32 | 
             
                    def initialize(options = {})
         | 
| 33 33 | 
             
                      @log = get_logger
         | 
| 34 34 | 
             
                      self.extend Splash::Daemon::Metrics
         | 
| 35 | 
            -
                      @ | 
| 35 | 
            +
                      @session = get_session
         | 
| 36 | 
            +
                      @metric_manager = get_metrics_manager(@session)
         | 
| 36 37 | 
             
                      $stdout.sync = true
         | 
| 37 38 | 
             
                      $stderr.sync = true
         | 
| 38 39 | 
             
                      @server  = Rufus::Scheduler::new
         | 
| 39 40 | 
             
                      @server.extend SchedulerHooks
         | 
| 40 41 | 
             
                      @config = get_config
         | 
| 42 | 
            +
                      @scheduling = options[:scheduling]
         | 
| 41 43 |  | 
| 42 44 | 
             
                      @log.info "Splash Orchestrator starting :"
         | 
| 43 | 
            -
                      if  | 
| 44 | 
            -
                        @log.item "Initializing commands Scheduling."
         | 
| 45 | 
            +
                      if @scheduling then
         | 
| 46 | 
            +
                        @log.item "Initializing Sequences & commands Scheduling."
         | 
| 45 47 | 
             
                        init_commands_scheduling
         | 
| 46 48 | 
             
                        init_sequences_scheduling
         | 
| 47 49 | 
             
                      end
         | 
| 48 50 |  | 
| 51 | 
            +
                      init_logs_monitoring_scheduling
         | 
| 52 | 
            +
                      init_process_monitoring_scheduling
         | 
| 53 | 
            +
                      init_metrics_scheduling
         | 
| 54 | 
            +
                      init_daemon_subscriber
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
             | 
| 59 | 
            +
             | 
| 60 | 
            +
             | 
| 61 | 
            +
             | 
| 62 | 
            +
                    # Stop the Splash daemon gracefully
         | 
| 63 | 
            +
                    # @return [hash] Exiter Case :quiet_exit
         | 
| 64 | 
            +
                    def terminate
         | 
| 65 | 
            +
                      @log.info "Splash daemon shutdown"
         | 
| 66 | 
            +
                      @server.shutdown
         | 
| 67 | 
            +
                      change_logger logger: :cli
         | 
| 68 | 
            +
                      splash_exit case: :quiet_exit
         | 
| 69 | 
            +
                    end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                    private
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    #prepare main daemon subscriber
         | 
| 74 | 
            +
                    def init_daemon_subscriber
         | 
| 75 | 
            +
                      hostname = Socket.gethostname
         | 
| 76 | 
            +
                      transport = get_default_subscriber queue: "splash.#{hostname}.input"
         | 
| 77 | 
            +
                      if transport.class == Hash and transport.include? :case then
         | 
| 78 | 
            +
                        splash_exit transport
         | 
| 79 | 
            +
                      end
         | 
| 80 | 
            +
                      transport.subscribe(:block => true) do |delivery_info, properties, body|
         | 
| 81 | 
            +
                        content = YAML::load(body)
         | 
| 82 | 
            +
                        session = get_session
         | 
| 83 | 
            +
                        content[:session] = session
         | 
| 84 | 
            +
                        if VERBS.include? content[:verb]
         | 
| 85 | 
            +
                          @log.receive "Valid remote order, verb : #{content[:verb].to_s}", session
         | 
| 86 | 
            +
                          res = self.send content[:verb], content
         | 
| 87 | 
            +
                          get_default_client.publish queue: content[:return_to], message: res.to_yaml
         | 
| 88 | 
            +
                          @log.send "Result to #{content[:return_to]}.", session
         | 
| 89 | 
            +
                        else
         | 
| 90 | 
            +
                          @log.receive "INVALID remote order, verb : #{content[:verb].to_s}", session
         | 
| 91 | 
            +
                          get_default_client.publish queue: content[:return_to], message: "Unkown verb #{content[:verb]}".to_yaml
         | 
| 92 | 
            +
                        end
         | 
| 93 | 
            +
                      end
         | 
| 94 | 
            +
                    end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                    #prepare logs monitoring  sheduling
         | 
| 97 | 
            +
                    def init_logs_monitoring_scheduling
         | 
| 49 98 | 
             
                      if @config.logs.empty? then
         | 
| 50 99 | 
             
                        @log.item "No logs to monitor"
         | 
| 51 100 | 
             
                      else
         | 
| @@ -64,7 +113,10 @@ module Splash | |
| 64 113 | 
             
                          end
         | 
| 65 114 | 
             
                        end
         | 
| 66 115 | 
             
                      end
         | 
| 116 | 
            +
                    end
         | 
| 67 117 |  | 
| 118 | 
            +
                    #prepare process monitoring  sheduling
         | 
| 119 | 
            +
                    def init_process_monitoring_scheduling
         | 
| 68 120 | 
             
                      if @config.processes.empty? then
         | 
| 69 121 | 
             
                        @log.item "No processes to monitor"
         | 
| 70 122 | 
             
                      else
         | 
| @@ -83,49 +135,24 @@ module Splash | |
| 83 135 | 
             
                          end
         | 
| 84 136 | 
             
                        end
         | 
| 85 137 | 
             
                      end
         | 
| 138 | 
            +
                    end
         | 
| 86 139 |  | 
| 87 140 |  | 
| 141 | 
            +
                    #prepare metrics sheduling
         | 
| 142 | 
            +
                    def init_metrics_scheduling
         | 
| 88 143 | 
             
                      sched,value = @config.daemon_metrics_scheduling.flatten
         | 
| 89 144 | 
             
                      @log.item "Initializing Splash metrics notifications."
         | 
| 90 145 | 
             
                      @server.send sched,value do
         | 
| 91 146 | 
             
                        begin
         | 
| 147 | 
            +
                          @log.trigger "Splash Metrics monitoring for Scheduling : #{sched.to_s} #{value.to_s}", @session
         | 
| 92 148 | 
             
                          @metric_manager.notify
         | 
| 93 149 | 
             
                        rescue Errno::ECONNREFUSED
         | 
| 94 150 | 
             
                          @log.error "PushGateway seems to be done, please start it."
         | 
| 95 151 | 
             
                        end
         | 
| 96 152 | 
             
                      end
         | 
| 97 | 
            -
             | 
| 98 | 
            -
                      hostname = Socket.gethostname
         | 
| 99 | 
            -
                      transport = get_default_subscriber queue: "splash.#{hostname}.input"
         | 
| 100 | 
            -
                      if transport.class == Hash and transport.include? :case then
         | 
| 101 | 
            -
                        splash_exit transport
         | 
| 102 | 
            -
                      end
         | 
| 103 | 
            -
                      transport.subscribe(:block => true) do |delivery_info, properties, body|
         | 
| 104 | 
            -
                        content = YAML::load(body)
         | 
| 105 | 
            -
                        session = get_session
         | 
| 106 | 
            -
                        content[:session] = session
         | 
| 107 | 
            -
                        if VERBS.include? content[:verb]
         | 
| 108 | 
            -
                          @log.receive "Valid remote order, verb : #{content[:verb].to_s}", session
         | 
| 109 | 
            -
                          res = self.send content[:verb], content
         | 
| 110 | 
            -
                          get_default_client.publish queue: content[:return_to], message: res.to_yaml
         | 
| 111 | 
            -
                          @log.send "Result to #{content[:return_to]}.", session
         | 
| 112 | 
            -
                        else
         | 
| 113 | 
            -
                          @log.receive "INVALID remote order, verb : #{content[:verb].to_s}", session
         | 
| 114 | 
            -
                          get_default_client.publish queue: content[:return_to], message: "Unkown verb #{content[:verb]}".to_yaml
         | 
| 115 | 
            -
                        end
         | 
| 116 | 
            -
                      end
         | 
| 117 153 | 
             
                    end
         | 
| 118 154 |  | 
| 119 | 
            -
                    # Stop the Splash daemon gracefully
         | 
| 120 | 
            -
                    # @return [hash] Exiter Case :quiet_exit
         | 
| 121 | 
            -
                    def terminate
         | 
| 122 | 
            -
                      @log.info "Splash daemon shutdown"
         | 
| 123 | 
            -
                      @server.shutdown
         | 
| 124 | 
            -
                      change_logger logger: :cli
         | 
| 125 | 
            -
                      splash_exit case: :quiet_exit
         | 
| 126 | 
            -
                    end
         | 
| 127 155 |  | 
| 128 | 
            -
                    private
         | 
| 129 156 | 
             
                    # prepare commands Scheduling
         | 
| 130 157 | 
             
                    def init_commands_scheduling
         | 
| 131 158 | 
             
                      config = get_config.commands
         | 
| @@ -139,7 +166,6 @@ module Splash | |
| 139 166 | 
             
                          execute command: command.to_s, session: session
         | 
| 140 167 | 
             
                        end
         | 
| 141 168 | 
             
                      end
         | 
| 142 | 
            -
             | 
| 143 169 | 
             
                    end
         | 
| 144 170 |  | 
| 145 171 |  | 
| @@ -156,9 +182,25 @@ module Splash | |
| 156 182 | 
             
                          run_seq name: sequence.to_s, session: session
         | 
| 157 183 | 
             
                        end
         | 
| 158 184 | 
             
                      end
         | 
| 159 | 
            -
             | 
| 160 185 | 
             
                    end
         | 
| 161 186 |  | 
| 187 | 
            +
                    # reset the orchestrator
         | 
| 188 | 
            +
                    # @return [Hash] Exiter case
         | 
| 189 | 
            +
                    def reset_orchestrator
         | 
| 190 | 
            +
                      @server.shutdown
         | 
| 191 | 
            +
                      @server = Rufus::Scheduler::new
         | 
| 192 | 
            +
                      @server.extend SchedulerHooks
         | 
| 193 | 
            +
                      @config = rehash_config
         | 
| 194 | 
            +
                      @log.info "Splash Orchestrator re-hashing :"
         | 
| 195 | 
            +
                      if @scheduling then
         | 
| 196 | 
            +
                        @log.item "Re-Initializing Sequences & commands Scheduling."
         | 
| 197 | 
            +
                        init_commands_scheduling
         | 
| 198 | 
            +
                        init_sequences_scheduling
         | 
| 199 | 
            +
                      end
         | 
| 200 | 
            +
                      init_logs_monitoring_scheduling
         | 
| 201 | 
            +
                      init_process_monitoring_scheduling
         | 
| 202 | 
            +
                      init_metrics_scheduling
         | 
| 203 | 
            +
                    end
         | 
| 162 204 |  | 
| 163 205 |  | 
| 164 206 | 
             
                    # execute_command verb : execute command specified in payload
         | 
| @@ -174,9 +216,7 @@ module Splash | |
| 174 216 | 
             
                        return command.call_and_notify trace: true, notify: true, callback: true, session: options[:session]
         | 
| 175 217 | 
             
                      end
         | 
| 176 218 | 
             
                    end
         | 
| 177 | 
            -
             | 
| 178 219 | 
             
                  end
         | 
| 179 | 
            -
             | 
| 180 220 | 
             
                end
         | 
| 181 221 | 
             
              end
         | 
| 182 222 | 
             
            end
         | 
| @@ -16,7 +16,7 @@ module Splash | |
| 16 16 | 
             
                    include Splash::Loggers
         | 
| 17 17 |  | 
| 18 18 | 
             
                    # list of known verbs for Splash orchestrator
         | 
| 19 | 
            -
                    VERBS=[:ping,:list_commands,:execute_command,:ack_command, :shutdown]
         | 
| 19 | 
            +
                    VERBS=[:ping,:list_commands,:execute_command,:ack_command, :shutdown, :get_jobs, :reset]
         | 
| 20 20 |  | 
| 21 21 | 
             
                    # shutdown verb : stop the Splash daemon gracefully
         | 
| 22 22 | 
             
                    # @param [Hash] content message content Hash Structure, ignored
         | 
| @@ -46,6 +46,21 @@ module Splash | |
| 46 46 | 
             
                      return execute command: content[:payload][:name], ack: true
         | 
| 47 47 | 
             
                    end
         | 
| 48 48 |  | 
| 49 | 
            +
             | 
| 50 | 
            +
                    # get_jobs verb : return list of scheduled jobs for internal scheduler
         | 
| 51 | 
            +
                    # @param [Hash] content message content Hash Structure, ignored
         | 
| 52 | 
            +
                    # @return [String] YAML dataset
         | 
| 53 | 
            +
                    def get_jobs(content)
         | 
| 54 | 
            +
                      return @server.jobs.to_yaml
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    # reset verb : reset the internal scheduler
         | 
| 58 | 
            +
                    # @param [Hash] content message content Hash Structure, ignored
         | 
| 59 | 
            +
                    # @return [String] "Scheduler reset" static
         | 
| 60 | 
            +
                    def reset(content)
         | 
| 61 | 
            +
                      return "Scheduler reset" if reset_orchestrator
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
             | 
| 49 64 | 
             
                    # execute_command verb : execute command specified in payload
         | 
| 50 65 | 
             
                    # @param [Hash] content message content Hash Structure, include  mandatory payload[:name]
         | 
| 51 66 | 
             
                    # @return [Hash] Exiter case
         | 
    
        data/lib/splash/dependencies.rb
    CHANGED
    
    | @@ -17,8 +17,12 @@ module Splash | |
| 17 17 |  | 
| 18 18 |  | 
| 19 19 |  | 
| 20 | 
            +
             | 
| 21 | 
            +
             | 
| 20 22 | 
             
                # Rubygems
         | 
| 21 23 | 
             
                begin
         | 
| 24 | 
            +
                  require 'net/ssh'
         | 
| 25 | 
            +
                  require 'net/scp'
         | 
| 22 26 | 
             
                  require 'prometheus/client'
         | 
| 23 27 | 
             
                  require 'prometheus/client/push'
         | 
| 24 28 | 
             
                  require 'thor'
         | 
| @@ -35,6 +39,7 @@ module Splash | |
| 35 39 | 
             
                  require 'rest-client'
         | 
| 36 40 | 
             
                  require 'kramdown'
         | 
| 37 41 | 
             
                  require 'rack/reverse_proxy'
         | 
| 42 | 
            +
                  require 'tty-table'
         | 
| 38 43 |  | 
| 39 44 |  | 
| 40 45 | 
             
                rescue Gem::GemNotFoundException
         | 
| @@ -57,9 +62,9 @@ module Splash | |
| 57 62 |  | 
| 58 63 | 
             
                require 'splash/commands'
         | 
| 59 64 | 
             
                require 'splash/sequences'
         | 
| 60 | 
            -
             | 
| 61 65 | 
             
                require 'splash/logs'
         | 
| 62 66 | 
             
                require 'splash/processes'
         | 
| 67 | 
            +
                require 'splash/transfers'
         | 
| 63 68 |  | 
| 64 69 | 
             
                require 'splash/daemon'
         | 
| 65 70 | 
             
                require 'splash/webadmin'
         | 
    
        data/lib/splash/helpers.rb
    CHANGED
    
    | @@ -252,7 +252,7 @@ module Splash | |
| 252 252 | 
             
                # check folder
         | 
| 253 253 | 
             
                # @return [Array] of Symbol with error type : [:inexistant,:mode,:owner,:group]
         | 
| 254 254 | 
             
                # @param [Hash] options
         | 
| 255 | 
            -
                # @option options [String] : | 
| 255 | 
            +
                # @option options [String] :name folder path (relative or absolute)
         | 
| 256 256 | 
             
                # @option options [String] :mode String for OCTAL rights like "644", optionnal
         | 
| 257 257 | 
             
                # @option options [String] :owner file owner for folder, optionnal
         | 
| 258 258 | 
             
                # @option options [String] :group  file group for folder, optionnal
         | 
| @@ -336,7 +336,6 @@ module Splash | |
| 336 336 | 
             
                end
         | 
| 337 337 | 
             
                #!@endgroup
         | 
| 338 338 |  | 
| 339 | 
            -
             | 
| 340 339 | 
             
                def format_response(data, format)
         | 
| 341 340 | 
             
                  response = case format
         | 
| 342 341 | 
             
                             when 'application/json' then JSON.pretty_generate(data)
         | 
| @@ -355,6 +354,16 @@ module Splash | |
| 355 354 | 
             
                   return result[extension]
         | 
| 356 355 | 
             
                end
         | 
| 357 356 |  | 
| 357 | 
            +
                # check if unicode must be used with term ENV
         | 
| 358 | 
            +
                # @return [Boolean]
         | 
| 359 | 
            +
                def check_unicode_term
         | 
| 360 | 
            +
                  return false unless ENV.include? "TERM"
         | 
| 361 | 
            +
                  if ENV.values_at("LC_ALL","LC_CTYPE","LANG").compact.first.include?("UTF-8") and ENV.values_at('TERM').first.include? "xterm" then
         | 
| 362 | 
            +
                    return true
         | 
| 363 | 
            +
                  else
         | 
| 364 | 
            +
                    return false
         | 
| 365 | 
            +
                  end
         | 
| 366 | 
            +
                end
         | 
| 358 367 |  | 
| 359 368 | 
             
              end
         | 
| 360 369 | 
             
            end
         | 
    
        data/lib/splash/loggers/cli.rb
    CHANGED
    
    | @@ -10,6 +10,7 @@ module Splash | |
| 10 10 | 
             
                class Cli < Splash::Loggers::LoggerTemplate
         | 
| 11 11 |  | 
| 12 12 | 
             
                  include Splash::Config
         | 
| 13 | 
            +
                  include Splash::Helpers
         | 
| 13 14 |  | 
| 14 15 | 
             
                  # mapping of UTf-8 emoji for log levels or alias
         | 
| 15 16 | 
             
                  EMOJI =  { :unknown => "\u{1F4A5}",
         | 
| @@ -82,16 +83,7 @@ module Splash | |
| 82 83 | 
             
                    get_config.loggers[:cli][:color] = status
         | 
| 83 84 | 
             
                  end
         | 
| 84 85 |  | 
| 85 | 
            -
             | 
| 86 | 
            -
                  # @return [Boolean]
         | 
| 87 | 
            -
                  def check_unicode_term
         | 
| 88 | 
            -
                    return false unless ENV.include? "TERM"
         | 
| 89 | 
            -
                    if ENV.values_at("LC_ALL","LC_CTYPE","LANG").compact.first.include?("UTF-8") and ENV.values_at('TERM').first.include? "xterm" then
         | 
| 90 | 
            -
                      return true
         | 
| 91 | 
            -
                    else
         | 
| 92 | 
            -
                      return false
         | 
| 93 | 
            -
                    end
         | 
| 94 | 
            -
                  end
         | 
| 86 | 
            +
             | 
| 95 87 |  | 
| 96 88 | 
             
                end
         | 
| 97 89 |  | 
| @@ -0,0 +1,224 @@ | |
| 1 | 
            +
            # coding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # base Splash Module
         | 
| 4 | 
            +
            module Splash
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              # Transfers module
         | 
| 7 | 
            +
              module Transfers
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                include Splash::Config
         | 
| 10 | 
            +
                include Splash::Loggers
         | 
| 11 | 
            +
                include Splash::Helpers
         | 
| 12 | 
            +
             | 
| 13 | 
            +
             | 
| 14 | 
            +
             | 
| 15 | 
            +
                class TxNotifier
         | 
| 16 | 
            +
                  @@registry = Prometheus::Client::Registry::new
         | 
| 17 | 
            +
                  @@metric_nbfiles = Prometheus::Client::Gauge.new(:txnbfiles, docstring: 'SPLASH metric transfer number of files')
         | 
| 18 | 
            +
                  @@metric_nbfiles_failed = Prometheus::Client::Gauge.new(:txnbfilesfailed, docstring: 'SPLASH metric transfer number of failed files')
         | 
| 19 | 
            +
                  @@metric_time = Prometheus::Client::Gauge.new(:txtime, docstring: 'SPLASH metric transfer execution time')
         | 
| 20 | 
            +
                  @@registry.register(@@metric_nbfiles)
         | 
| 21 | 
            +
                  @@registry.register(@@metric_nbfiles_failed)
         | 
| 22 | 
            +
                  @@registry.register(@@metric_time)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def initialize(options={})
         | 
| 25 | 
            +
                    @config = get_config
         | 
| 26 | 
            +
                    @url = @config.prometheus_pushgateway_url
         | 
| 27 | 
            +
                    @name = "tx_#{options[:name].to_s}"
         | 
| 28 | 
            +
                    @nbfiles = options[:nbfiles]
         | 
| 29 | 
            +
                    @nbfiles_failed = options[:nbfiles_failed]
         | 
| 30 | 
            +
                    @time = options[:time]
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  # send metrics to Prometheus PushGateway
         | 
| 34 | 
            +
                  # @return [Bool]
         | 
| 35 | 
            +
                  def notify
         | 
| 36 | 
            +
            	unless verify_service url: @url then
         | 
| 37 | 
            +
                      return { :case => :service_dependence_missing, :more => "Prometheus Notification not send."}
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
                    @@metric_nbfiles.set(@nbfiles)
         | 
| 40 | 
            +
                    @@metric_nbfiles_failed.set(@nbfiles_failed)
         | 
| 41 | 
            +
                    @@metric_time.set(@time)
         | 
| 42 | 
            +
                    hostname = Socket.gethostname
         | 
| 43 | 
            +
                    return Prometheus::Client::Push.new(@name, hostname, @url).add(@@registry)
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
             | 
| 49 | 
            +
             | 
| 50 | 
            +
                class TxRecords
         | 
| 51 | 
            +
                  include Splash::Backends
         | 
| 52 | 
            +
                  def initialize(name)
         | 
| 53 | 
            +
                    @name = name
         | 
| 54 | 
            +
                    @backend = get_backend :transferts_trace
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  def purge(retention)
         | 
| 58 | 
            +
                    if retention.include? :hours then
         | 
| 59 | 
            +
                      adjusted_datetime = DateTime.now - retention[:hours].to_f / 24
         | 
| 60 | 
            +
                    elsif retention.include? :hours then
         | 
| 61 | 
            +
                      adjusted_datetime = DateTime.now - retention[:days].to_i
         | 
| 62 | 
            +
                    else
         | 
| 63 | 
            +
                      retention = TRANSFER_DEFAULT_RETENTION
         | 
| 64 | 
            +
                    end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                    data = get_all_records
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                    data.delete_if { |item,value|
         | 
| 69 | 
            +
                      DateTime.parse(item) <= (adjusted_datetime) and value[:status] != :prepared}
         | 
| 70 | 
            +
                    @backend.put key: @name, value: data.to_yaml
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  def add_record(record)
         | 
| 74 | 
            +
                    data = get_all_records
         | 
| 75 | 
            +
                    data[DateTime.now.to_s] = record
         | 
| 76 | 
            +
                    @backend.put key: @name, value: data.to_yaml
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  def get_all_records
         | 
| 80 | 
            +
                    return (@backend.exist?({key: @name}))? YAML::load(@backend.get({key: @name})) : {}
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                  def check_prepared
         | 
| 84 | 
            +
                    return :never_run_prepare unless @backend.exist?({key: @name})
         | 
| 85 | 
            +
                    return :never_prepare unless YAML::load(@backend.get({key: @name})).select {|item,value|
         | 
| 86 | 
            +
                      value[:status] == :prepared
         | 
| 87 | 
            +
                    }.count > 0
         | 
| 88 | 
            +
                    return :prepared
         | 
| 89 | 
            +
                  end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                def run_txs(options = {})
         | 
| 94 | 
            +
                  log = get_logger
         | 
| 95 | 
            +
                  log.info 'Running Transfers'
         | 
| 96 | 
            +
                  count=0
         | 
| 97 | 
            +
                  get_config.transfers.each do |record|
         | 
| 98 | 
            +
                    txrec =  TxRecords::new record[:name]
         | 
| 99 | 
            +
                    txrec.purge(record[:retention])
         | 
| 100 | 
            +
                    log.item "Execute : #{record[:name]},  #{record[:desc]}"
         | 
| 101 | 
            +
                    case txrec.check_prepared
         | 
| 102 | 
            +
                    when :prepared
         | 
| 103 | 
            +
                      if record[:type] == :push then
         | 
| 104 | 
            +
                        unless push record
         | 
| 105 | 
            +
                          count += 1
         | 
| 106 | 
            +
                        end
         | 
| 107 | 
            +
                      elsif record[:type] == :pull then
         | 
| 108 | 
            +
                        unless pull record
         | 
| 109 | 
            +
                          count += 1
         | 
| 110 | 
            +
                        end
         | 
| 111 | 
            +
                      else
         | 
| 112 | 
            +
                        log.ko "Transfer type unkown"
         | 
| 113 | 
            +
                        count += 1
         | 
| 114 | 
            +
                      end
         | 
| 115 | 
            +
                    when :never_prepare
         | 
| 116 | 
            +
                      log.ko "#{record[:name]} : Never prepared, ignored"
         | 
| 117 | 
            +
                      txrec.add_record :status => :never_prepared
         | 
| 118 | 
            +
                      count += 1
         | 
| 119 | 
            +
                    when :never_run_prepare
         | 
| 120 | 
            +
                      log.ko "#{record[:name]} : Never Executed and never prepared, ignored"
         | 
| 121 | 
            +
                      txrec.add_record :status => :never_prepared
         | 
| 122 | 
            +
                      count += 1
         | 
| 123 | 
            +
                    end
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
                  return {:case => :error_exit, :more => "#{count} Transfer(s) failed"} if count > 0
         | 
| 126 | 
            +
                  return {:case => :quiet_exit }
         | 
| 127 | 
            +
                end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
             | 
| 130 | 
            +
             | 
| 131 | 
            +
                def prepare_tx(name)
         | 
| 132 | 
            +
                  log = get_logger
         | 
| 133 | 
            +
                  record = get_config.transfers.select { |item| item[:name] == name.to_sym }.first
         | 
| 134 | 
            +
                  home  = Etc.getpwnam(record[:local][:user]).dir
         | 
| 135 | 
            +
                  identity = ::File::readlines("#{home}/.ssh/id_rsa.pub").first.chomp
         | 
| 136 | 
            +
                  folder  = {:mode => "755",
         | 
| 137 | 
            +
                             :owner => record[:local][:user] ,
         | 
| 138 | 
            +
                             :group => Etc.getgrgid(Etc.getpwnam(record[:local][:user]).gid).name,
         | 
| 139 | 
            +
                             :name => record[:local][:path],
         | 
| 140 | 
            +
                             :path => record[:local][:path]}
         | 
| 141 | 
            +
                  log.info "Ensure local folder : #{record[:local][:path]}"
         | 
| 142 | 
            +
                  make_folder(folder) unless verify_folder(folder).empty?
         | 
| 143 | 
            +
                  begin
         | 
| 144 | 
            +
                    log.info "Ensure RSA Key sharing for local user : #{record[:local][:user]} to remote user : #{record[:remote][:user]}@#{record[:remote][:host]}"
         | 
| 145 | 
            +
                    ssh = Net::SSH.start(record[:remote][:host],record[:remote][:user])
         | 
| 146 | 
            +
                    output = ssh.exec!(%[
         | 
| 147 | 
            +
                      /bin/bash -cl '
         | 
| 148 | 
            +
                      umask 077;
         | 
| 149 | 
            +
                      mkdir #{record[:remote][:path]};
         | 
| 150 | 
            +
                      test -d ~/.ssh || mkdir ~/.ssh;
         | 
| 151 | 
            +
                      if [ ! -f ~/.ssh/authorized_keys -o `grep "#{identity}" ~/.ssh/authorized_keys 2> /dev/null | wc -l` -eq 0 ]; then              echo "#{identity}" >> ~/.ssh/authorized_keys
         | 
| 152 | 
            +
                      fi'])
         | 
| 153 | 
            +
                    log.info "Prepare remote folder : #{record[:remote][:path]}"
         | 
| 154 | 
            +
                    log.info "Prepare data file for transfer : #{record[:name]}"
         | 
| 155 | 
            +
                    txrec = TxRecords::new record[:name]
         | 
| 156 | 
            +
                    txrec.add_record :status => :prepared
         | 
| 157 | 
            +
                    log.ok "Transfer : #{record[:name]} prepared successfully"
         | 
| 158 | 
            +
                    return {:case => :quiet_exit }
         | 
| 159 | 
            +
                  rescue Interrupt
         | 
| 160 | 
            +
                    splash_exit case: :interrupt, more: "Remote command exection"
         | 
| 161 | 
            +
                  rescue TTY::Reader::InputInterrupt
         | 
| 162 | 
            +
                    splash_exit case: :interrupt, more: "Remote command exection"
         | 
| 163 | 
            +
                  end
         | 
| 164 | 
            +
                end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
             | 
| 167 | 
            +
             | 
| 168 | 
            +
                def save_data
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                end
         | 
| 171 | 
            +
             | 
| 172 | 
            +
             | 
| 173 | 
            +
             | 
| 174 | 
            +
                def push(record)
         | 
| 175 | 
            +
                  config = get_config
         | 
| 176 | 
            +
                  log = get_logger
         | 
| 177 | 
            +
                  txrec = TxRecords::new record[:name]
         | 
| 178 | 
            +
                  start = Time.now
         | 
| 179 | 
            +
                  res = true
         | 
| 180 | 
            +
                  count = 0
         | 
| 181 | 
            +
                  done =[]
         | 
| 182 | 
            +
                  start_date = DateTime.now.to_s
         | 
| 183 | 
            +
                  list = Dir.glob("#{record[:local][:path]}/#{record[:pattern]}")
         | 
| 184 | 
            +
                  count = list.count
         | 
| 185 | 
            +
                  log.arrow "Transfering #{count} file(s)"
         | 
| 186 | 
            +
             | 
| 187 | 
            +
                  begin
         | 
| 188 | 
            +
                    scp = Net::SCP.start(record[:remote][:host],record[:remote][:user])
         | 
| 189 | 
            +
                    list.each do|f|
         | 
| 190 | 
            +
                      log.arrow "Copy file : #{f} to #{record[:remote][:user]}@#{record[:remote][:host]}:#{record[:remote][:path]}"
         | 
| 191 | 
            +
                      scp.upload! f, record[:remote][:path]
         | 
| 192 | 
            +
                      done.push f
         | 
| 193 | 
            +
                      if record[:backup] then
         | 
| 194 | 
            +
                        log.arrow "File #{f} backuped"
         | 
| 195 | 
            +
                        FileUtils::mv(f, "#{f}.#{Time.now.getutc.to_i}")
         | 
| 196 | 
            +
                      else
         | 
| 197 | 
            +
                        FileUtils::unlink(f)
         | 
| 198 | 
            +
                      end
         | 
| 199 | 
            +
                    end
         | 
| 200 | 
            +
             | 
| 201 | 
            +
                  rescue
         | 
| 202 | 
            +
                    res = false
         | 
| 203 | 
            +
                  end
         | 
| 204 | 
            +
             | 
| 205 | 
            +
                  end_date = DateTime.now.to_s
         | 
| 206 | 
            +
                  time = Time.now - start
         | 
| 207 | 
            +
                  status = (res)? :success : :failure
         | 
| 208 | 
            +
                  txrec.add_record :status => status,
         | 
| 209 | 
            +
                                   :end_date => end_date,
         | 
| 210 | 
            +
                                   :time => time,
         | 
| 211 | 
            +
                                   :count => count,
         | 
| 212 | 
            +
                                   :wanted => list,
         | 
| 213 | 
            +
                                   :done => done
         | 
| 214 | 
            +
                  count_failed = list.count - done.count
         | 
| 215 | 
            +
                  txmonitor = TxNotifier::new({name: record[:name], nbfiles: count,nbfiles_failed: count_failed, time: time})
         | 
| 216 | 
            +
                  if txmonitor.notify then
         | 
| 217 | 
            +
                    log.ok "Sending metrics to Prometheus Pushgateway"
         | 
| 218 | 
            +
                  else
         | 
| 219 | 
            +
                    log.ko "Failed to send metrics to Prometheus Pushgateway"
         | 
| 220 | 
            +
                  end
         | 
| 221 | 
            +
                  return res
         | 
| 222 | 
            +
                end
         | 
| 223 | 
            +
              end
         | 
| 224 | 
            +
            end
         |