def testUnresolvedVariable(self): service_yaml = 'src/resources/yaml/integration/myservice-unresolved-variable.yml' try: lighter.parse_service(service_yaml) except RuntimeError as e: self.assertEquals(e.message, 'Failed to parse %s with the following message: Variable %%{bvar} not found' % service_yaml) else: self.fail('Expected RuntimeError')
def testParseListOverride(self): # servicePort=1234 in json, no override in yaml service = lighter.parse_service('src/resources/yaml/staging/myservice-serviceport-nooverride.yml') self.assertEquals(service.config['container']['docker']['portMappings'][0]['servicePort'], 1234) # servicePort=1234 in json, override with servicePort=4000 in yaml service = lighter.parse_service('src/resources/yaml/staging/myservice-serviceport-override.yml') self.assertEquals(service.config['container']['docker']['portMappings'][0]['servicePort'], 4000)
def testNonStringEnvkey(self): service_yaml = 'src/resources/yaml/integration/myservice-nonstring-envkey.yml' try: lighter.parse_service(service_yaml) except ValueError as e: self.assertEquals(e.message, 'Only string dict keys are supported, please use quotes around the key \'True\' in %s' % service_yaml) else: self.fail('Expected ValueError')
def testConfigHash(self): service1 = lighter.parse_service('src/resources/yaml/staging/myservice.yml') service2 = lighter.parse_service('src/resources/yaml/staging/myservice.yml') self.assertEqual(32, len(service1.config['labels']['com.meltwater.lighter.checksum'])) self.assertEqual(service1.config['labels']['com.meltwater.lighter.checksum'], service2.config['labels']['com.meltwater.lighter.checksum']) service3 = lighter.parse_service('src/resources/yaml/staging/myservice-classifier.yml') self.assertNotEqual(service1.config['labels']['com.meltwater.lighter.checksum'], service3.config['labels']['com.meltwater.lighter.checksum'])
def testServiceWithEnvvarDots(self): try: lighter.parse_service('src/resources/yaml/staging/myservice-encrypted-dots.yml') except RuntimeError as e: self.assertEquals( "The env var 'database.uri' is not a valid shell script identifier and not supported by Secretary. " + "Only alphanumeric characters and underscores are supported, starting with an alphabetic or underscore character.", e.message) else: self.fail("Expected exception RuntimeError")
def testRedeployWithoutChange(self): service1 = lighter.parse_service('src/resources/yaml/staging/myservice-servicekey.yml') service2 = lighter.parse_service('src/resources/yaml/staging/myservice-servicekey.yml') self.assertNotEqual(service1.config, service2.config) checksum1 = util.rget(service1.config, 'labels', 'com.meltwater.lighter.checksum') self.assertIsNotNone(checksum1) self.assertEqual(checksum1, util.rget(service2.config, 'labels', 'com.meltwater.lighter.checksum')) self.assertNotEqual(service1.config['env']['DEPLOY_PUBLIC_KEY'], service2.config['env']['DEPLOY_PUBLIC_KEY']) self.assertNotEqual(service1.config['env']['DEPLOY_PRIVATE_KEY'], service2.config['env']['DEPLOY_PRIVATE_KEY'])
def testParseEnvVariable(self): os.environ['VERSION'] = '1.0.0' os.environ['DATABASE'] = 'hostname:3306' os.environ['RABBITMQ_URL'] = 'amqp://hostname:5672/%2F' service = lighter.parse_service('src/resources/yaml/staging/myservice-env-variable.yml') self.assertEquals(service.config['container']['docker']['image'], 'meltwater/myservice:1.0.0') self.assertEquals(service.config['env']['DATABASE'], 'hostname:3306') service = lighter.parse_service('src/resources/yaml/staging/myservice-env-maven.yml') self.assertEquals(service.config['container']['docker']['image'], 'meltwater/myservice:1.0.0') self.assertEquals(service.config['env']['DATABASE'], 'hostname:3306') self.assertEquals(service.config['env']['RABBITMQ_URL'], 'amqp://hostname:5672/%2F')
def testParseNonDockerService(self): service = lighter.parse_service('src/resources/yaml/staging/myservice-non-docker.yml') self.assertEquals(service.config['id'], '/myservice/hello-play') self.assertEquals(service.config['cpus'], 1) self.assertEquals(service.config['instances'], 1) self.assertFalse('container' in service.config)
def testParseNoMavenService(self): service = lighter.parse_service("src/resources/yaml/staging/myservice-nomaven.yml") self.assertEquals(service.document["hipchat"]["token"], "abc123") self.assertEquals(service.config["id"], "/myproduct/myservice-nomaven") self.assertEquals(service.config["instances"], 1) self.assertEquals(service.config["env"]["DATABASE"], "database:3306") self.assertEquals(service.config["container"]["docker"]["image"], "meltwater/myservice:latest")
def testParseNoMavenService(self): service = lighter.parse_service('src/resources/yaml/staging/myservice-nomaven.yml', profiles=[PROFILE_1, PROFILE_2]) self.assertEquals(service.document['hipchat']['token'], 'abc123') self.assertEquals(service.config['id'], '/myproduct/myservice-nomaven') self.assertEquals(service.config['instances'], 1) self.assertEquals(service.config['env']['DATABASE'], 'database:3306') self.assertEquals(service.config['container']['docker']['image'], 'meltwater/myservice:latest')
def testNonStringEnvvar(self): service = lighter.parse_service('src/resources/yaml/integration/myservice-nonstring-envvar.yml') self.assertEquals('123', service.config['env']['INTVAR']) self.assertEquals('123.456', service.config['env']['FLOATVAR']) self.assertEquals('true', service.config['env']['TRUEVAR']) self.assertEquals('false', service.config['env']['FALSEVAR']) self.assertEquals('{"foobar": [1, 2], "foo": "bar", "bar": 123}', service.config['env']['COMPLEXVAR'])
def testPrivateV1Auth(self): url = 'http://*****:*****@authregistrywithport:5000/v1/repositories/library/myservice/tags/1.2.3' data = "30e6fc5eecc6e76733cf7881ee965335aae73d7c1bc7ca9817ecccbf925a4647" with patch('lighter.util.jsonRequest', wraps=self._wrapRequest(url, data)): service = lighter.parse_service('src/resources/yaml/staging/myservice-docker-private-auth.yml') self.assertEquals(service.config['env']['SERVICE_VERSION'], '1.2.3') self.assertEquals(service.config['env']['SERVICE_BUILD'], '30e6fc5eecc6e76733cf7881ee965335aae73d7c1bc7ca9817ecccbf925a4647') self.assertTrue(self._dockerRegistryCalled)
def testPrivateV1Repo(self): url = 'https://registry.example.com/v1/repositories/myrepo/myservice/tags/latest' data = "30e6fc5eecc6e76733cf7881ee965335aae73d7c1bc7ca9817ecccbf925a4647" with patch('lighter.util.jsonRequest', wraps=self._wrapRequest(url, data)): service = lighter.parse_service('src/resources/yaml/staging/myservice-docker-private-repo.yml') self.assertEquals(service.config['env']['SERVICE_VERSION'], 'latest') self.assertEquals(service.config['env']['SERVICE_BUILD'], '30e6fc5eecc6e76733cf7881ee965335aae73d7c1bc7ca9817ecccbf925a4647') self.assertTrue(self._dockerRegistryCalled)
def testWriteServices(self): service1 = lighter.parse_service( 'src/resources/yaml/staging/myservice.yml') service2 = lighter.parse_service( 'src/resources/yaml/staging/myservice-non-docker.yml') targetdir = tempfile.mkdtemp(prefix='lighter-deploy_test') try: lighter.write_services(targetdir, [service1, service2]) self.assertTrue( os.path.exists( '%s/src/resources/yaml/staging/myservice.yml.json' % targetdir)) self.assertTrue( os.path.exists( '%s/src/resources/yaml/staging/myservice-non-docker.yml.json' % targetdir)) finally: shutil.rmtree(targetdir)
def testPasswordCheckWarning(self, mock_warn): lighter.verify_secrets([ lighter.parse_service( 'src/resources/yaml/staging/myservice-password.yml') ], enforce=False) self.assertEqual(mock_warn.call_count, 1) mock_warn.assert_called_with( 'Found unencrypted secret in src/resources/yaml/staging/myservice-password.yml: DATABASE_PASSWORD' )
def testParseNoMavenService(self): service = lighter.parse_service( 'src/resources/yaml/staging/myservice-nomaven.yml', profiles=[PROFILE_1, PROFILE_2]) self.assertEquals(service.document['hipchat']['token'], 'abc123') self.assertEquals(service.config['id'], '/myproduct/myservice-nomaven') self.assertEquals(service.config['instances'], 1) self.assertEquals(service.config['env']['DATABASE'], 'database:3306') self.assertEquals(service.config['container']['docker']['image'], 'meltwater/myservice:latest')
def testPrivateV2(self): url = 'http://registrywithport.example.com:5000/v2/myservice/manifests/1.2.3' data = {"schemaVersion": 1, "history": [ { "v1Compatibility": "{\"id\":\"30e6fc5eecc6e76733cf7881ee965335aae73d7c1bc7ca9817ecccbf925a4647\",\"parent\":\"b90ac02561d777b67829f428d73e78dca2adb3cf5bbd4e1ad152a330e88281b7\",\"created\":\"2015-11-23T12:56:12.819222551Z\",\"container\":\"a6cb5f2df76e9755f987bb5638eb7a56e11a221ee7083657c5e5c6167be01a5c\",\"container_config\":{\"Hostname\":\"afbbf75ae75d\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) ENTRYPOINT \\u0026{[\\\"/lighter\\\"]}\"],\"Image\":\"b90ac02561d777b67829f428d73e78dca2adb3cf5bbd4e1ad152a330e88281b7\",\"Volumes\":{\"/site\":{}},\"WorkingDir\":\"/site\",\"Entrypoint\":[\"/lighter\"],\"OnBuild\":[],\"Labels\":null},\"docker_version\":\"1.8.3-rc4\",\"config\":{\"Hostname\":\"afbbf75ae75d\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":null,\"Image\":\"b90ac02561d777b67829f428d73e78dca2adb3cf5bbd4e1ad152a330e88281b7\",\"Volumes\":{\"/site\":{}},\"WorkingDir\":\"/site\",\"Entrypoint\":[\"/lighter\"],\"OnBuild\":[],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\"}"}, # noqa { "v1Compatibility": "{\"id\":\"b90ac02561d777b67829f428d73e78dca2adb3cf5bbd4e1ad152a330e88281b7\",\"parent\":\"277d2a07471445a484d24d352e57ac42ff7e8a31e1da06a0fccd578bba26ff17\",\"created\":\"2015-11-23T12:56:12.232870097Z\",\"container\":\"4200b3984c2ea437937b6fb0e43cfe2f61507217cdbda050f5b53ecc4f63b026\",\"container_config\":{\"Hostname\":\"afbbf75ae75d\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) WORKDIR /site\"],\"Image\":\"277d2a07471445a484d24d352e57ac42ff7e8a31e1da06a0fccd578bba26ff17\",\"Volumes\":{\"/site\":{}},\"WorkingDir\":\"/site\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"docker_version\":\"1.8.3-rc4\",\"config\":{\"Hostname\":\"afbbf75ae75d\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":null,\"Image\":\"277d2a07471445a484d24d352e57ac42ff7e8a31e1da06a0fccd578bba26ff17\",\"Volumes\":{\"/site\":{}},\"WorkingDir\":\"/site\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\"}"}, # noqa ]} with patch('lighter.util.jsonRequest', wraps=self._wrapRequest(url, data)): service = lighter.parse_service('src/resources/yaml/staging/myservice-docker-private.yml') self.assertEquals(service.config['env']['SERVICE_VERSION'], '1.2.3') self.assertEquals(service.config['env']['SERVICE_BUILD'], '30e6fc5eecc6e76733cf7881ee965335aae73d7c1bc7ca9817ecccbf925a4647') self.assertTrue(self._dockerRegistryCalled)
def testPrivateV1Repo(self): url = 'https://registry.example.com/v1/repositories/myrepo/myservice/tags/latest' data = "30e6fc5eecc6e76733cf7881ee965335aae73d7c1bc7ca9817ecccbf925a4647" with patch('lighter.util.jsonRequest', wraps=self._wrapRequest(url, data)): service = lighter.parse_service( 'src/resources/yaml/staging/myservice-docker-private-repo.yml') self.assertEquals(service.config['env']['SERVICE_VERSION'], 'latest') self.assertEquals( service.config['env']['SERVICE_BUILD'], '30e6fc5eecc6e76733cf7881ee965335aae73d7c1bc7ca9817ecccbf925a4647' ) self.assertTrue(self._dockerRegistryCalled)
def testPrivateV1Auth(self): url = 'http://*****:*****@authregistrywithport:5000/v1/repositories/library/myservice/tags/1.2.3' data = "30e6fc5eecc6e76733cf7881ee965335aae73d7c1bc7ca9817ecccbf925a4647" with patch('lighter.util.jsonRequest', wraps=self._wrapRequest(url, data)): service = lighter.parse_service( 'src/resources/yaml/staging/myservice-docker-private-auth.yml') self.assertEquals(service.config['env']['SERVICE_VERSION'], '1.2.3') self.assertEquals( service.config['env']['SERVICE_BUILD'], '30e6fc5eecc6e76733cf7881ee965335aae73d7c1bc7ca9817ecccbf925a4647' ) self.assertTrue(self._dockerRegistryCalled)
def testParseService(self): service = lighter.parse_service("src/resources/yaml/staging/myservice.yml") self.assertEquals(service.document["hipchat"]["token"], "abc123") self.assertEquals(sorted(service.document["hipchat"]["rooms"]), ["123", "456", "456", "789"]) self.assertEquals(service.environment, "staging") self.assertEquals(service.config["id"], "/myproduct/myservice") self.assertEquals(service.config["env"]["DATABASE"], "database:3306") self.assertEquals(service.config["env"]["rabbitmq"], "amqp://myserver:15672") self.assertEquals(service.config["cpus"], 1) self.assertEquals(service.config["instances"], 3) self.assertEquals(service.config["env"]["SERVICE_VERSION"], "1.0.0") self.assertEquals(service.config["env"]["SERVICE_BUILD"], "1.0.0") # Check that zero are translated correctly self.assertEquals(service.config["upgradeStrategy"]["minimumHealthCapacity"], 0.0) self.assertEquals(service.config["upgradeStrategy"]["maximumOverCapacity"], 0.0)
def testParseService(self): service = lighter.parse_service('src/resources/yaml/staging/myservice.yml', profiles=[PROFILE_1, PROFILE_2]) self.assertEquals(service.document['hipchat']['token'], 'abc123') self.assertEquals(sorted(service.document['hipchat']['rooms']), ['123', '456', '456', '789']) self.assertEquals(service.environment, 'staging') self.assertEquals(service.config['id'], '/myproduct/myservice') self.assertEquals(service.config['env']['DATABASE'], 'database:3306') self.assertEquals(service.config['env']['rabbitmq'], 'amqp://myserver:15672') self.assertEquals(service.config['cpus'], 1) self.assertEquals(service.config['instances'], 3) self.assertEquals(service.config['env']['SERVICE_VERSION'], '1.0.0') self.assertEquals(service.config['env']['SERVICE_BUILD'], '1.0.0') self.assertEquals(service.config['env']['MY_ESCAPED_VAR'], '%{id}') self.assertEquals(service.config['container']['docker']['parameters'][0]['key'], 'label') self.assertEquals(service.config['container']['docker']['parameters'][0]['value'], 'com.meltwater.lighter.appid='+service.config['id']) # Check that zero are translated correctly self.assertEquals(service.config['upgradeStrategy']['minimumHealthCapacity'], 0.0) self.assertEquals(service.config['upgradeStrategy']['maximumOverCapacity'], 0.0)
def testDeployNotify(self, mock_time, mock_socket, mock_jsonRequest): mock_sock = Mock() mock_socket.return_value = mock_sock service = lighter.parse_service('src/resources/yaml/integration/graphite-config-tags.yml') lighter.notify('http://localhost:8080/', service) mock_jsonRequest.assert_called_with( 'http://localhost:80/events/', method='POST', data={ 'what': 'Deployed /myproduct/myservice to the default environment', 'data': 'Lighter deployed /myproduct/myservice with image meltwater/myservice:latest to default (localhost:8080)', 'tags': 'environment:default service:/myproduct/myservice somekey:someval anotherkey:anotherval ' + 'justakey es_ca_pe trimwhitespace source:lighter type:change', 'when': 1477507464}) self.assertEquals(1, mock_sock.connect.call_count) mock_sock.connect.assert_called_with(('localhost', 2003)) self.assertEquals(1, mock_sock.send.call_count) mock_sock.send.assert_called_with("ci.lighter.default.myproduct.myservice.deployments 1 1477507464\n") self.assertEquals(1, mock_sock.close.call_count)
def testAddMasterKey(self): service = lighter.parse_service('src/resources/yaml/staging/myservice.yml') self.assertEquals(service.config['env']['MASTER_PUBLIC_KEY'], 'pq01FdTbzF7q29HiX8f01oDfQyHgVFw03vEZes7OtnQ=')
def testServiceWithEmbeddedSecret(self): service = lighter.parse_service('src/resources/yaml/staging/myservice-embedded-encrypted-url.yml') self.assertTrue('SECRETARY_URL' in service.config['env']) self.assertTrue('DEPLOY_PUBLIC_KEY' in service.config['env']) self.assertTrue('DEPLOY_PRIVATE_KEY' in service.config['env'])
def testPasswordCheckSubstringsSucceed(self): lighter.parse_service('src/resources/yaml/staging/myservice-encrypted-substrings.yml', verifySecrets=True)
def testUnresolvedVariable(self): try: lighter.parse_service("src/resources/yaml/integration/myservice-unresolved-variable.yml") except KeyError, e: self.assertEquals(e.message, "Variable %{bvar} not found")
def testParseUniqueSnapshot(self): service = lighter.parse_service("src/resources/yaml/staging/myservice-unique-snapshot.yml") self.assertEquals(service.config["env"]["SERVICE_VERSION"], "1.1.1-SNAPSHOT") self.assertEquals(service.config["env"]["SERVICE_BUILD"], "1.1.1-20151102.035053-8-marathon")
def testParseRecursiveVariable(self): service = lighter.parse_service("src/resources/yaml/staging/myservice.yml") self.assertEquals(service.config["env"]["BVAR"], "123") self.assertEquals(service.config["env"]["CVAR"], "123")
def testParseRecursiveVariable(self): service = lighter.parse_service( 'src/resources/yaml/staging/myservice.yml') self.assertEquals(service.config['env']['BVAR'], '123') self.assertEquals(service.config['env']['CVAR'], '123')
def testPasswordCheckFail(self): with self.assertRaises(RuntimeError): lighter.parse_service('src/resources/yaml/staging/myservice-password.yml', verifySecrets=True)
def testParseUniqueSnapshot(self): service = lighter.parse_service('src/resources/yaml/staging/myservice-unique-snapshot.yml') self.assertEquals(service.config['env']['SERVICE_VERSION'], '1.1.1-SNAPSHOT') self.assertEquals(service.config['env']['SERVICE_BUILD'], '1.1.1-20151102.035053-8-marathon')
def testParseClassifier(self): service = lighter.parse_service('src/resources/yaml/staging/myservice-classifier.yml') self.assertEquals(service.config['env']['isclassifier'], 'marathon') self.assertEquals(service.config['env']['SERVICE_VERSION'], '1.0.0') self.assertEquals(service.config['env']['SERVICE_BUILD'], '1.0.0-marathon')
def testPasswordCheckFail(self): with self.assertRaises(RuntimeError): lighter.parse_service( 'src/resources/yaml/staging/myservice-password.yml', verifySecrets=True)
def testPasswordCheckSubstringsSucceed(self): lighter.parse_service( 'src/resources/yaml/staging/myservice-encrypted-substrings.yml', verifySecrets=True)
def testPasswordCheckSucceed(self): lighter.verify_secrets([ lighter.parse_service( 'src/resources/yaml/staging/myservice-encrypted-password.yml') ], enforce=True)
def testParseClassifier(self): service = lighter.parse_service("src/resources/yaml/staging/myservice-classifier.yml") self.assertEquals(service.config["env"]["isclassifier"], "marathon") self.assertEquals(service.config["env"]["SERVICE_VERSION"], "1.0.0") self.assertEquals(service.config["env"]["SERVICE_BUILD"], "1.0.0-marathon")
def testParseSnapshot(self): service = lighter.parse_service("src/resources/yaml/staging/myservice-snapshot.yml") self.assertEquals(service.config["env"]["SERVICE_VERSION"], "1.1.1-SNAPSHOT") self.assertEquals(service.config["env"]["SERVICE_BUILD"], "1.1.1-20151105011659-4")
def testAddDeployKey(self): service = lighter.parse_service('src/resources/yaml/staging/myservice.yml') self.assertIsNotNone(service.config['env']['DEPLOY_PUBLIC_KEY']) self.assertIsNotNone(service.config['env']['DEPLOY_PRIVATE_KEY'])
def testServiceWithoutSecrets(self): service = lighter.parse_service('src/resources/yaml/staging/myservice-nosecret.yml') self.assertFalse('SECRETARY_URL' in service.config['env']) self.assertFalse('MASTER_PRIVATE_KEY' in service.config['env']) self.assertFalse('DEPLOY_PUBLIC_KEY' in service.config['env']) self.assertFalse('DEPLOY_PRIVATE_KEY' in service.config['env'])
def testParseRecursiveVariable(self): service = lighter.parse_service('src/resources/yaml/staging/myservice.yml') self.assertEquals(service.config['env']['BVAR'], '123') self.assertEquals(service.config['env']['CVAR'], '123')
def testPasswordCheckWarning(self, mock_warn): lighter.parse_service('src/resources/yaml/staging/myservice-password.yml', verifySecrets=False) self.assertEqual(mock_warn.call_count, 1) mock_warn.assert_called_with('Found unencrypted secret in src/resources/yaml/staging/myservice-password.yml: DATABASE_PASSWORD')