Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

# Licensed under the Apache License, Version 2.0 (the "License"); 

# you may not use this file except in compliance with the License. 

#    You may obtain a copy of the License at 

# 

#        http://www.apache.org/licenses/LICENSE-2.0 

# 

#    Unless required by applicable law or agreed to in writing, software 

#    distributed under the License is distributed on an "AS IS" BASIS, 

#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

#    See the License for the specific language governing permissions and 

#    limitations under the License. 

 

"""Magnum Docker RPC handler.""" 

 

from docker import errors 

from oslo_config import cfg 

 

from magnum.common import docker_utils 

from magnum.common import exception 

from magnum.common import utils 

from magnum.conductor.handlers.common import docker_client 

from magnum import objects 

from magnum.objects import container as obj_container 

from magnum.openstack.common import log as logging 

 

LOG = logging.getLogger(__name__) 

CONF = cfg.CONF 

 

docker_opts = [ 

    cfg.StrOpt('docker_remote_api_version', 

               default=docker_client.DEFAULT_DOCKER_REMOTE_API_VERSION, 

               help='Docker remote api version. Override it according to ' 

                    'specific docker api version in your environment.'), 

    cfg.IntOpt('default_timeout', 

               default=docker_client.DEFAULT_DOCKER_TIMEOUT, 

               help='Default timeout in seconds for docker client ' 

                    'operations.'), 

    cfg.BoolOpt('api_insecure', 

                default=False, 

                help='If set, ignore any SSL validation issues'), 

    cfg.StrOpt('ca_file', 

               help='Location of CA certificates file for ' 

                    'securing docker api requests (tlscacert).'), 

    cfg.StrOpt('cert_file', 

               help='Location of TLS certificate file for ' 

                    'securing docker api requests (tlscert).'), 

    cfg.StrOpt('key_file', 

               help='Location of TLS private key file for ' 

                    'securing docker api requests (tlskey).'), 

] 

 

CONF.register_opts(docker_opts, 'docker') 

 

 

class Handler(object): 

 

    def __init__(self): 

        super(Handler, self).__init__() 

 

    @staticmethod 

    def _find_container_by_name(docker, name): 

        try: 

            for info in docker.list_instances(inspect=True): 

                if info['Config'].get('Hostname') == name: 

                    return info 

        except errors.APIError as e: 

            if e.response.status_code != 404: 

                raise 

        return {} 

 

    def _encode_utf8(self, value): 

        return unicode(value).encode('utf-8') 

 

    @staticmethod 

    def _docker_for_bay(bay): 

        tcp_url = 'tcp://%s:2376' % bay.api_address 

        return docker_client.DockerHTTPClient(tcp_url, 

                                    CONF.docker.docker_remote_api_version, 

                                    CONF.docker.default_timeout) 

 

    @classmethod 

    def _docker_for_container(cls, context, container): 

        bay = objects.Bay.get_by_uuid(context, container.bay_uuid) 

        return cls._docker_for_bay(bay) 

 

    @classmethod 

    def get_docker_client(cls, context, container): 

        if utils.is_uuid_like(container): 

            container = objects.Container.get_by_uuid(context, container) 

        return cls._docker_for_container(context, container) 

 

    # Container operations 

 

    def container_create(self, context, name, container_uuid, container): 

        docker = self.get_docker_client(context, container) 

        image_id = container.image_id 

        LOG.debug('Creating container with image %s name %s' 

                  % (image_id, name)) 

        try: 

            image_repo, image_tag = docker_utils.parse_docker_image(image_id) 

            docker.pull(image_repo, tag=image_tag) 

            docker.inspect_image(self._encode_utf8(container.image_id)) 

            docker.create_container(image_id, name=name, 

                                    hostname=container_uuid, 

                                    command=container.command) 

            container.status = obj_container.STOPPED 

            return container 

        except errors.APIError as api_error: 

            container.status = obj_container.ERROR 

            raise exception.ContainerException( 

                      "Docker API Error : %s" % str(api_error)) 

        finally: 

            container.save() 

 

    def container_delete(self, context, container_uuid): 

        LOG.debug("container_delete %s" % container_uuid) 

        docker = self.get_docker_client(context, container_uuid) 

        try: 

            docker_id = self._find_container_by_name(docker, container_uuid) 

            if not docker_id: 

                return None 

            return docker.remove_container(docker_id) 

        except errors.APIError as api_error: 

            raise exception.ContainerException( 

                      "Docker API Error : %s" % str(api_error)) 

 

    def container_show(self, context, container_uuid): 

        LOG.debug("container_show %s" % container_uuid) 

        docker = self.get_docker_client(context, container_uuid) 

        container = objects.Container.get_by_uuid(context, container_uuid) 

        try: 

            docker_id = self._find_container_by_name(docker, container_uuid) 

            result = docker.inspect_container(docker_id) 

            status = result.get('State') 

145            if status: 

                if status.get('Error') is True: 

                    container.status = obj_container.ERROR 

                elif status.get('Running'): 

                    container.status = obj_container.RUNNING 

                elif status.get('Paused'): 

                    container.status = obj_container.PAUSED 

                else: 

                    container.status = obj_container.STOPPED 

                container.save() 

            return container 

        except errors.APIError as api_error: 

            error_message = str(api_error) 

            if '404' in error_message: 

                container.status = obj_container.ERROR 

                container.save() 

                return container 

            raise exception.ContainerException( 

                      "Docker API Error : %s" % (error_message)) 

 

    def _container_action(self, context, container_uuid, status, docker_func): 

        LOG.debug("container_%s %s" % (status, container_uuid)) 

        docker = self.get_docker_client(context, container_uuid) 

        try: 

            docker_id = self._find_container_by_name(docker, container_uuid) 

            result = getattr(docker, docker_func)(docker_id) 

            container = objects.Container.get_by_uuid(context, container_uuid) 

            container.status = status 

            container.save() 

            return result 

        except errors.APIError as api_error: 

            raise exception.ContainerException( 

                      "Docker API Error : %s" % str(api_error)) 

 

    def container_reboot(self, context, container_uuid): 

        return self._container_action(context, container_uuid, 

                                      obj_container.RUNNING, 'restart') 

 

    def container_stop(self, context, container_uuid): 

        return self._container_action(context, container_uuid, 

                                      obj_container.STOPPED, 'stop') 

 

    def container_start(self, context, container_uuid): 

        return self._container_action(context, container_uuid, 

                                      obj_container.RUNNING, 'start') 

 

    def container_pause(self, context, container_uuid): 

        return self._container_action(context, container_uuid, 

                                      obj_container.PAUSED, 'pause') 

 

    def container_unpause(self, context, container_uuid): 

        return self._container_action(context, container_uuid, 

                                      obj_container.RUNNING, 'unpause') 

 

    def container_logs(self, context, container_uuid): 

        LOG.debug("container_logs %s" % container_uuid) 

        docker = self.get_docker_client(context, container_uuid) 

        try: 

            docker_id = self._find_container_by_name(docker, container_uuid) 

            return {'output': docker.get_container_logs(docker_id)} 

        except errors.APIError as api_error: 

            raise exception.ContainerException( 

                      "Docker API Error : %s" % str(api_error)) 

 

    def container_execute(self, context, container_uuid, command): 

        LOG.debug("container_execute %s command %s" % 

                  (container_uuid, command)) 

        docker = self.get_docker_client(context, container_uuid) 

        try: 

            docker_id = self._find_container_by_name(docker, container_uuid) 

            return {'output': docker.execute(docker_id, command)} 

        except errors.APIError as api_error: 

            raise exception.ContainerException( 

                      "Docker API Error : %s" % str(api_error))