def test_remove_inactive_containers_succeeds(self): container_name = "clipper/noop-container:{}".format(clipper_version) input_type = "doubles" model_name = "remove-inactive-test-model" self.clipper_conn.build_and_deploy_model(model_name, 1, input_type, fake_model_data, container_name, num_replicas=2) docker_client = get_docker_client() containers = docker_client.containers.list( filters={"ancestor": container_name}) self.assertEqual(len(containers), 2) self.clipper_conn.build_and_deploy_model(model_name, 2, input_type, fake_model_data, container_name, num_replicas=3) containers = docker_client.containers.list( filters={"ancestor": container_name}) self.assertEqual(len(containers), 5) self.clipper_conn.stop_inactive_model_versions([model_name]) containers = docker_client.containers.list( filters={"ancestor": container_name}) self.assertEqual(len(containers), 3)
def get_containers(self, container_name): return get_docker_client().containers.list( filters={ "ancestor": container_name, "label": "{key}={val}".format(key=CLIPPER_DOCKER_LABEL, val=self.clipper_conn.cm.cluster_name) })
def test_register_py_endpoint(self): name = "py-closure-test" expected_version = 1 def predict_func(inputs): return ["0" for x in inputs] input_type = "doubles" create_py_endpoint(self.clipper_conn, name, input_type, predict_func) registered_applications = self.clipper_conn.get_all_apps() self.assertEqual(len(registered_applications), 1) self.assertTrue(name in registered_applications) registered_model_info = self.clipper_conn.get_model_info( name, expected_version) self.assertIsNotNone(registered_model_info) linked_models = self.clipper_conn.get_linked_models(name) self.assertIsNotNone(linked_models) docker_client = get_docker_client() py_minor_version = (sys.version_info.major, sys.version_info.minor) if py_minor_version < (3, 0): containers = docker_client.containers.list( filters={ "ancestor": "clipper/python-closure-container:{}".format( clipper_version) }) elif py_minor_version == (3, 5): containers = docker_client.containers.list( filters={ "ancestor": "clipper/python35-closure-container:{}".format( clipper_version) }) elif py_minor_version == (3, 6): containers = docker_client.containers.list( filters={ "ancestor": "clipper/python36-closure-container:{}".format( clipper_version) }) else: msg = ( "Python closure deployer only supports Python 2.7, 3.5, and 3.6. " "Detected {major}.{minor}").format( major=sys.version_info.major, minor=sys.version_info.minor) logger.error(msg) self.assertEqual(len(containers), 1)
def test_model_deploys_successfully(self): model_name = "m" version = "v1" container_name = "clipper/noop-container:{}".format(clipper_version) input_type = "doubles" self.clipper_conn.build_and_deploy_model(model_name, version, input_type, fake_model_data, container_name) model_info = self.clipper_conn.get_model_info(model_name, version) self.assertIsNotNone(model_info) self.assertEqual(type(model_info), dict) docker_client = get_docker_client() containers = docker_client.containers.list( filters={"ancestor": container_name}) self.assertEqual(len(containers), 1)
def test_python_closure_deploys_successfully(self): model_name = "m2" model_version = 1 def predict_func(inputs): return ["0" for x in inputs] input_type = "doubles" deploy_python_closure(self.clipper_conn, model_name, model_version, input_type, predict_func) model_info = self.clipper_conn.get_model_info(model_name, model_version) self.assertIsNotNone(model_info) docker_client = get_docker_client() py_minor_version = (sys.version_info.major, sys.version_info.minor) if py_minor_version < (3, 0): containers = docker_client.containers.list( filters={ "ancestor": "clipper/python-closure-container:{}".format( clipper_version) }) elif py_minor_version == (3, 5): containers = docker_client.containers.list( filters={ "ancestor": "clipper/python35-closure-container:{}".format( clipper_version) }) elif py_minor_version == (3, 6): containers = docker_client.containers.list( filters={ "ancestor": "clipper/python36-closure-container:{}".format( clipper_version) }) else: msg = ( "Python closure deployer only supports Python 2.7, 3.5, and 3.6. " "Detected {major}.{minor}").format( major=sys.version_info.major, minor=sys.version_info.minor) logger.error(msg) self.assertGreaterEqual(len(containers), 1)
def test_stop_models(self): container_name = "clipper/noop-container:{}".format(clipper_version) input_type = "doubles" mnames = ["jimmypage", "robertplant", "jpj", "johnbohnam"] versions = ["i", "ii", "iii", "iv"] for model_name in mnames: for version in versions: self.clipper_conn.deploy_model(model_name, version, input_type, container_name, num_replicas=1) docker_client = get_docker_client() containers = docker_client.containers.list( filters={"ancestor": container_name}) self.assertEqual(len(containers), len(mnames) * len(versions)) # stop all versions of models jimmypage, robertplant self.clipper_conn.stop_models(mnames[:2]) containers = docker_client.containers.list( filters={"ancestor": container_name}) self.assertEqual(len(containers), len(mnames[2:]) * len(versions)) # After calling this method, the remaining models should be: # jpj:i, jpj:iii, johnbohman:ii self.clipper_conn.stop_versioned_models({ "jpj": ["ii", "iv"], "johnbohnam": ["i", "iv", "iii"], }) containers = docker_client.containers.list( filters={"ancestor": container_name}) self.assertEqual(len(containers), 3) self.clipper_conn.stop_all_model_containers() containers = docker_client.containers.list( filters={"ancestor": container_name}) self.assertEqual(len(containers), 0)
def test_remove_inactive_container(self): container_name = "clipper/noop-container:{}".format(clipper_version) self.clipper_conn.build_and_deploy_model(self.model_name_5, 1, self.input_type, fake_model_data, container_name, num_replicas=2) docker_client = get_docker_client() containers = docker_client.containers.list( filters={"ancestor": container_name}) self.assertEqual(len(containers), 2) self.clipper_conn.link_model_to_app(self.app_name_5, self.model_name_5) time.sleep(30) # We now have 2 replicas running, both the same model name and Version # send predictions, assert that we are getting correct response addr = self.clipper_conn.get_query_addr() test_input = [101.1, 99.5, 107.2] req_json = json.dumps({'input': test_input}) headers = {'Content-type': 'application/json'} for i in range(2): response = requests.post("http://%s/%s/predict" % (addr, self.app_name_5), headers=headers, data=req_json) result = response.json() self.assertEqual(response.status_code, requests.codes.ok) #print(result["default_explanation"]) self.assertEqual(result["default"], False) # one of the containers should go inactive self.clipper_conn.set_num_replicas(name=self.model_name_5, version=1, num_replicas=1) time.sleep(100) containers = docker_client.containers.list( filters={"ancestor": container_name}) self.assertEqual(len(containers), 1) test_input = [101.1, 99.9] req_json = json.dumps({'input': test_input}) #send predictions, should still be working for i in range(2): response = requests.post("http://%s/%s/predict" % (addr, self.app_name_5), headers=headers, data=req_json) result = response.json() self.assertEqual(response.status_code, requests.codes.ok) self.assertEqual(result["default"], False) #2nd container should go inactive self.clipper_conn.set_num_replicas(name=self.model_name_5, version=1, num_replicas=0) time.sleep(100) containers = docker_client.containers.list( filters={"ancestor": container_name}) self.assertEqual(len(containers), 0) test_input = [101.1] req_json = json.dumps({'input': test_input}) #send predictions, should be getting response with message 'no connected models' for i in range(2): response = requests.post("http://%s/%s/predict" % (addr, self.app_name_5), headers=headers, data=req_json) result = response.json() self.assertEqual(result["default"], True) self.assertEqual(result["default_explanation"], "No connected models found for query")