Welcome to mirror list, hosted at ThFree Co, Russian Federation.

base.rb « docker_run « service « qa « qa - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 1796ea0b5f8ab5a1f009195173a31524fa75cf21 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# frozen_string_literal: true

require 'socket'

module QA
  module Service
    module DockerRun
      # TODO: There are a lot of methods that reference @name yet it is not part of initializer
      # Refactor all child implementations to remove assumption that @name will exist
      #
      class Base
        include Service::Shellout

        def self.authenticated_registries
          @authenticated_registries ||= {}
        end

        def initialize
          @network = Runtime::Scenario.attributes[:network] || Runtime::Env.docker_network || 'test'
        end

        # Authenticate against a container registry
        # If authentication is successful, will cache registry
        #
        # @param registry [String] registry to authenticate against
        # @param user [String]
        # @param password [String]
        # @param force [Boolean] force authentication if already authenticated
        # @return [Void]
        def login(registry, user:, password:, force: false)
          return if self.class.authenticated_registries[registry] && !force

          shell(
            %(docker login --username "#{user}" --password "#{password}" #{registry}),
            mask_secrets: [password]
          )

          self.class.authenticated_registries[registry] = true
        end

        def logs
          shell "docker logs #{@name}"
        end

        def network
          return @network_cache if @network_cache

          @network_cache = network_exists?(@network) ? @network : 'bridge'
        end

        def inspect_network(name)
          shell("docker network inspect #{name}", fail_on_exception: false, return_exit_status: true)
        end

        def network_exists?(name)
          _, status = inspect_network(name)
          status == 0
        end

        def pull
          Support::Retrier.retry_until(retry_on_exception: true, sleep_interval: 3) do
            shell "docker pull #{@image}"
          end
        end

        # Host name of the container
        #
        # If host or default bridge network is used, container can only be reached using ip address
        #
        # @return [String]
        def host_name
          @host_name ||= if network == "host" || network == "bridge"
                           host_ip
                         else
                           "#{@name}.#{network}"
                         end
        end

        def register!
          raise NotImplementedError
        end

        def remove!
          shell "docker rm -f #{@name}" if running?
        end

        def running?
          `docker ps -f name=#{@name}`.include?(@name)
        end

        def read_file(file_path)
          `docker exec #{@name} /bin/cat #{file_path}`
        end

        def restart
          return "Container #{@name} is not running, cannot restart." unless running?

          shell "docker restart #{@name}"
        end

        def health
          shell("docker inspect --format='{{json .State.Health.Status}}' #{@name}").delete('"')
        end

        # Returns the IP address of the docker host
        #
        # @return [String]
        def host_ip
          docker_host = shell("docker context inspect --format='{{json .Endpoints.docker.Host}}'").delete('"')
          hostname = URI(docker_host).host
          # The docker host could be bound to a Unix socket, in which case as a URI it has no host
          host = hostname.presence || Socket.gethostname
          ip = Addrinfo.tcp(host, nil).ip_address
          ip == '0.0.0.0' ? '127.0.0.1' : ip
        rescue SocketError
          # If the host could not be resolved, fallback on localhost
          '127.0.0.1'
        end

        # Copy files to/from the Docker container and the host
        #
        # @param from the source path to copy files from
        # @param to the destination path to copy files to
        def copy(from:, to:)
          shell("docker cp #{from} #{to}")
        end
      end
    end
  end
end