Skip to content

Commit e557f75

Browse files
committed
FAB-3534: Add composition utilities
These are the Composition utilities that will be used in the system feature behave tests. Change-Id: I3e8b466edc43930c5646aa6b030a2bb8e131f3d7 Signed-off-by: Latitia M Haskins <[email protected]>
1 parent 16cb17a commit e557f75

File tree

1 file changed

+179
-0
lines changed

1 file changed

+179
-0
lines changed

test/feature/steps/compose_util.py

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# Copyright IBM Corp. 2016 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 = []):
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+
self.serviceNames = []
52+
self.serviceNames = self._collectServiceNames()
53+
self.up(context, force_recreate, components)
54+
55+
def _collectServiceNames(self):
56+
'First collect the services names.'
57+
servicesList = [service for service in self.issueCommand(["config", "--services"]).splitlines() if "WARNING" not in service]
58+
return servicesList
59+
60+
def up(self, context, force_recreate=True, components=[]):
61+
self.serviceNames = self._collectServiceNames()
62+
command = ["up", "-d"]
63+
if force_recreate:
64+
command += ["--force-recreate"]
65+
self.issueCommand(command + components)
66+
67+
def scale(self, context, serviceName, count=1):
68+
self.serviceNames = self._collectServiceNames()
69+
command = ["scale", "%s=%d" %(serviceName, count)]
70+
self.issueCommand(command)
71+
72+
def stop(self, context, components=[]):
73+
self.serviceNames = self._collectServiceNames()
74+
command = ["stop"]
75+
self.issueCommand(command, components)
76+
77+
def start(self, context, components=[]):
78+
self.serviceNames = self._collectServiceNames()
79+
command = ["start"]
80+
self.issueCommand(command, components)
81+
82+
def parseComposeFilesArg(self, composeFileArgs):
83+
composeFileList = []
84+
for composeFile in composeFileArgs.split():
85+
if not os.path.isdir(composeFile):
86+
composeFileList.append(composeFile)
87+
else:
88+
composeFileList.append(os.path.join(composeFile, 'docker-compose.yml'))
89+
90+
argSubList = [["-f", composeFile] for composeFile in composeFileList]
91+
args = [arg for sublist in argSubList for arg in sublist]
92+
return args
93+
94+
def getFileArgs(self):
95+
return self.parseComposeFilesArg(self.composeFilesYaml)
96+
97+
def getEnvAdditions(self):
98+
myEnv = {}
99+
myEnv["COMPOSE_PROJECT_NAME"] = self.projectName
100+
myEnv["CORE_PEER_NETWORKID"] = self.projectName
101+
return myEnv
102+
103+
def getEnv(self):
104+
myEnv = os.environ.copy()
105+
for key,value in self.getEnvAdditions().iteritems():
106+
myEnv[key] = value
107+
return myEnv
108+
109+
def refreshContainerIDs(self):
110+
containers = self.issueCommand(["ps", "-q"]).split()
111+
return containers
112+
113+
def getContainerIP(self, container):
114+
container_ipaddress = None
115+
if container['State']['Running']:
116+
container_ipaddress = container['NetworkSettings']['IPAddress']
117+
if not container_ipaddress:
118+
# ipaddress not found at the old location, try the new location
119+
container_ipaddress = container['NetworkSettings']['Networks'].values()[0]['IPAddress']
120+
return container_ipaddress
121+
122+
def issueCommand(self, command, components=[]):
123+
componentList = []
124+
useCompose = True
125+
for component in components:
126+
if '_' in component:
127+
useCompose = False
128+
componentList.append("%s_%s" % (self.projectName, component))
129+
else:
130+
break
131+
132+
# If we need to perform an operation on a specific container, use
133+
# docker not docker-compose
134+
if useCompose:
135+
cmdArgs = self.getFileArgs()+ command + components
136+
cmd = ["docker-compose"] + cmdArgs
137+
else:
138+
cmdArgs = command + componentList
139+
cmd = ["docker"] + cmdArgs
140+
141+
output = subprocess.check_output(cmd, env=self.getEnv())
142+
143+
# Don't rebuild if ps command
144+
if command[0] !="ps" and command[0] !="config":
145+
self.rebuildContainerData()
146+
return output
147+
148+
def rebuildContainerData(self):
149+
self.containerDataList = []
150+
for containerID in self.refreshContainerIDs():
151+
# get container metadata
152+
container = json.loads(subprocess.check_output(["docker", "inspect", containerID]))[0]
153+
# container name
154+
container_name = container['Name'][1:]
155+
# container ip address (only if container is running)
156+
container_ipaddress = self.getContainerIP(container)
157+
# container environment
158+
container_env = container['Config']['Env']
159+
# container exposed ports
160+
container_ports = container['NetworkSettings']['Ports']
161+
# container docker-compose service
162+
container_compose_service = container['Config']['Labels']['com.docker.compose.service']
163+
container_data = ContainerData(container_name,
164+
container_ipaddress,
165+
container_env,
166+
container_compose_service,
167+
container_ports)
168+
self.containerDataList.append(container_data)
169+
170+
def decompose(self):
171+
self.issueCommand(["unpause"])
172+
self.issueCommand(["down"])
173+
self.issueCommand(["kill"])
174+
self.issueCommand(["rm", "-f"])
175+
env = self.getEnv()
176+
177+
# Now remove associated chaincode containers if any
178+
cmd = ["docker", "ps", "-qa", "--filter", "name={0}".format(self.projectName)]
179+
output = subprocess.check_output(cmd, env=env)

0 commit comments

Comments
 (0)