nicholasjackson/minke

View on GitHub
lib/minke/tasks/task.rb

Summary

Maintainability
B
6 hrs
Test Coverage
module Minke
  module Tasks
    ##
    # Task is a base implementation of a rake task such as fetch, build, etc
    class Task

      def initialize args
        @config                 = args[:config]
        @task_name              = args[:task_name]
        @docker_runner          = args[:docker_runner]
        @task_runner            = args[:task_runner]
        @shell_helper           = args[:shell_helper]
        @logger                 = args[:logger_helper]
        @generator_config       = args[:generator_config]
        @docker_compose_factory = args[:docker_compose_factory]
        @consul                 = args[:consul]
        @docker_network         = args[:docker_network]
        @health_check           = args[:health_check]
        @service_discovery      = args[:service_discovery]
        @task_settings          = @config.send(@task_name) unless @task_name == :push
      end

      ##
      # run_with_config executes the task steps for the given
      # - block containing custom actions
      def run_with_block
        success = true

        begin
          @docker_network.create
          @consul.start_and_load_data @task_settings.consul_loader unless @task_settings.consul_loader == nil
          
          pre_func = -> {
            @task_runner.run_steps(@task_settings.pre) unless @task_settings == nil || @task_settings.pre == nil
          }

          post_func = -> {
            @task_runner.run_steps(@task_settings.post) unless @task_settings == nil || @task_settings.post == nil
          } 
          
          if block_given?
            yield(pre_func, post_func)
          else
            pre_func.call
            post_func.call
          end
        rescue Exception => e
          @logger.error e.message
          success = false
        ensure
          @consul.stop unless @task_settings.consul_loader == nil
          begin
            @docker_network.remove
          rescue Exception => e
            # Trap removing a network as minke may have been called with an existing network and containers
            # may still be attached.
            @logger.error e.message
          end
        end

        abort unless success
      end

      ##
      # runs the given command in a docker container
      def run_command_in_container(command, blocking = false, links = nil, ports = nil)
        begin
          @logger.info "Running command: #{command}"
          settings          = @generator_config.build_settings.docker_settings
          volumes           = settings.binds.clone unless settings.binds == nil
          environment       = settings.env.clone unless settings.env == nil
          build_image       = create_container_image
          working_directory = create_working_directory

          if ENV['AGENT_SOCK'] != nil
            volumes.push "#{ENV['AGENT_SOCK']}:/ssh-agent"
            environment.push "SSH_AUTH_SOCK=/ssh-agent"
            environment.push "GIT_SSH_COMMAND=ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
          end

          if @task_settings.consul_loader != nil && links != nil
            links.push "consul"
          end


          args = {
            :image             => build_image,
            :command           => command,
            :volumes           => volumes,
            :environment       => environment,
            :working_directory => working_directory,
            :links             => links,
            :ports             => ports,
          }

          if blocking == false
            container, success = @docker_runner.create_and_run_container args
          else 
            container, success = @docker_runner.create_and_run_blocking_container args
          end

          # throw exception if failed
          raise "Unable to run command #{command}" unless success
        ensure
          @docker_runner.delete_container container
        end
      end

      ##
      # Pulls the build image for the container from the registry if one is supplied,
      # if a build file is specified an image is built.
      def create_container_image
        build_image = @generator_config.build_settings.docker_settings.image
        build_image = @config.build_image_for(@task_name) unless @config.build_image_for(@task_name) == nil

        build_file = @config.build_docker_file_for(@task_name)

        if build_file != nil
          build_image = "#{@config.application_name}-buildimage"
          
          @logger.debug "Building image: #{build_image} from file #{build_file}"
          @docker_runner.build_image build_file, build_image
        else
          if (@docker_runner.find_image build_image) == nil
            @logger.debug "Pulling image: #{build_image}"
            @docker_runner.pull_image build_image         
          end
        end

        build_image
      end

      def create_working_directory
        base_path = @generator_config.build_settings.docker_settings.working_directory
        override_path = @task_settings.docker.working_directory unless @task_settings.docker == nil

        if override_path != nil
          path = Pathname.new(base_path)
          return (path + override_path).to_s
        else 
          return base_path
        end
      end

    end
  end
end