github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/test/feature/steps/compose_util.py (about)

     1  # Copyright IBM Corp. 2017 All Rights Reserved.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #      http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  #
    15  
    16  import os
    17  import subprocess
    18  import json
    19  import uuid
    20  
    21  
    22  class ContainerData:
    23      def __init__(self, containerName, ipAddress, envFromInspect, composeService, ports):
    24          self.containerName = containerName
    25          self.ipAddress = ipAddress
    26          self.envFromInspect = envFromInspect
    27          self.composeService = composeService
    28          self.ports = ports
    29  
    30      def getEnv(self, key):
    31          envValue = None
    32          for val in self.envFromInspect:
    33              if val.startswith(key):
    34                  envValue = val[len(key):]
    35                  break
    36          if envValue == None:
    37              raise Exception("ENV key not found ({0}) for container ({1})".format(key, self.containerName))
    38          return envValue
    39  
    40  
    41  class Composition:
    42  
    43      def __init__(self, context, composeFilesYaml, projectName = None,
    44                   force_recreate = True, components = [], startContainers=True):
    45          if not projectName:
    46              projectName = str(uuid.uuid1()).replace('-','')
    47          self.projectName = projectName
    48          self.context = context
    49          self.containerDataList = []
    50          self.composeFilesYaml = composeFilesYaml
    51          if startContainers:
    52              self.up(force_recreate, components)
    53  
    54      def collectServiceNames(self):
    55          'First collect the services names.'
    56          servicesList = [service for service in self.issueCommand(["config", "--services"]).splitlines() if "WARNING" not in service]
    57          return servicesList
    58  
    59      def up(self, force_recreate=True, components=[]):
    60          self.serviceNames = self.collectServiceNames()
    61          command = ["up", "-d"]
    62          if force_recreate:
    63              command += ["--force-recreate"]
    64          self.issueCommand(command + components)
    65  
    66      def scale(self, serviceName, count=1):
    67          self.serviceNames = self.collectServiceNames()
    68          command = ["scale", "%s=%d" %(serviceName, count)]
    69          self.issueCommand(command)
    70  
    71      def stop(self, components=[]):
    72          self.serviceNames = self.collectServiceNames()
    73          command = ["stop"]
    74          self.issueCommand(command, components)
    75  
    76      def start(self, components=[]):
    77          self.serviceNames = self.collectServiceNames()
    78          command = ["start"]
    79          self.issueCommand(command, components)
    80  
    81      def docker_exec(self, command, components=[]):
    82          results = {}
    83          updatedCommand = " ".join(command)
    84          for component in components:
    85              execCommand = ["exec", component, updatedCommand]
    86              results[component] = self.issueCommand(execCommand, [])
    87          return results
    88  
    89      def parseComposeFilesArg(self, composeFileArgs):
    90          composeFileList = []
    91          for composeFile in composeFileArgs.split():
    92              if not os.path.isdir(composeFile):
    93                  composeFileList.append(composeFile)
    94              else:
    95                  composeFileList.append(os.path.join(composeFile, 'docker-compose.yml'))
    96  
    97          argSubList = [["-f", composeFile] for composeFile in composeFileList]
    98          args = [arg for sublist in argSubList for arg in sublist]
    99          return args
   100  
   101      def getFileArgs(self):
   102          return self.parseComposeFilesArg(self.composeFilesYaml)
   103  
   104      def getEnvAdditions(self):
   105          myEnv = {}
   106          myEnv["COMPOSE_PROJECT_NAME"] = self.projectName
   107          myEnv["CORE_PEER_NETWORKID"] = self.projectName
   108          return myEnv
   109  
   110      def getEnv(self):
   111          myEnv = os.environ.copy()
   112          for key,value in self.getEnvAdditions().iteritems():
   113              myEnv[key] = value
   114          return myEnv
   115  
   116      def refreshContainerIDs(self):
   117          containers = self.issueCommand(["ps", "-q"]).split()
   118          return containers
   119  
   120      def getContainerIP(self, container):
   121          container_ipaddress = None
   122          if container['State']['Running']:
   123              container_ipaddress = container['NetworkSettings']['IPAddress']
   124              if not container_ipaddress:
   125                  # ipaddress not found at the old location, try the new location
   126                  container_ipaddress = container['NetworkSettings']['Networks'].values()[0]['IPAddress']
   127          return container_ipaddress
   128  
   129      def issueCommand(self, command, components=[]):
   130          componentList = []
   131          useCompose = True
   132          for component in components:
   133              if '_' in component:
   134                  useCompose = False
   135                  componentList.append("%s_%s" % (self.projectName, component))
   136              else:
   137                  break
   138  
   139          # If we need to perform an operation on a specific container, use
   140          # docker not docker-compose
   141          if useCompose:
   142              cmdArgs = self.getFileArgs()+ command + components
   143              cmd = ["docker-compose"] + cmdArgs
   144          else:
   145              cmdArgs = command + componentList
   146              cmd = ["docker"] + cmdArgs
   147  
   148          process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=self.getEnv())
   149          output, _error = process.communicate()
   150  
   151          # Don't rebuild if ps command
   152          if command[0] !="ps" and command[0] !="config":
   153              self.rebuildContainerData()
   154          return output
   155  
   156      def rebuildContainerData(self):
   157          self.containerDataList = []
   158          for containerID in self.refreshContainerIDs():
   159              # get container metadata
   160              container = json.loads(subprocess.check_output(["docker", "inspect", containerID]))[0]
   161              # container name
   162              container_name = container['Name'][1:]
   163              # container ip address (only if container is running)
   164              container_ipaddress = self.getContainerIP(container)
   165              # container environment
   166              container_env = container['Config']['Env']
   167              # container exposed ports
   168              container_ports = container['NetworkSettings']['Ports']
   169              # container docker-compose service
   170              container_compose_service = container['Config']['Labels']['com.docker.compose.service']
   171              container_data = ContainerData(container_name,
   172                                             container_ipaddress,
   173                                             container_env,
   174                                             container_compose_service,
   175                                             container_ports)
   176              self.containerDataList.append(container_data)
   177  
   178      def decompose(self):
   179          self.issueCommand(["unpause"])
   180          self.issueCommand(["down"])
   181          self.issueCommand(["kill"])
   182          self.issueCommand(["rm", "-f"])
   183          env = self.getEnv()
   184  
   185          # Now remove associated chaincode containers if any
   186          cmd = ["docker", "ps", "-qa", "--filter", "name={0}".format(self.projectName)]
   187          output = subprocess.check_output(cmd, env=env)