Skip to content

Commit 5989b9b

Browse files
committed
Added a jupyter creator plugin
1 parent 53b2c9e commit 5989b9b

File tree

5 files changed

+114
-17
lines changed

5 files changed

+114
-17
lines changed

api/src/main/resources/application_creator.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import uuid
3232
from importlib import import_module
3333
from exceptiondef import FailedValidation, FailedCreation
34+
from deployer_utils import HDFS
3435

3536

3637
class ApplicationCreator(object):
@@ -41,6 +42,9 @@ def __init__(self, config, environment, service):
4142
self._service = service
4243
self._component_creators = {}
4344
self._name_regex = re.compile('')
45+
self._hdfs_client = HDFS(environment['webhdfs_host'],
46+
environment['webhdfs_port'],
47+
'hdfs')
4448

4549
def create_application(self, package_data, package_metadata, application_name, property_overrides):
4650

@@ -76,6 +80,11 @@ def destroy_application(self, application_name, application_create_data):
7680
creator = self._load_creator(component_type)
7781
creator.destroy_components(application_name, component_create_data)
7882

83+
local_path = '/opt/%s/%s/' % (self._service, application_name)
84+
if os.path.isdir(local_path):
85+
os.rmdir(local_path)
86+
self._hdfs_client.remove('/user/%s' % application_name, recursive=False)
87+
7988
def start_application(self, application_name, application_create_data):
8089

8190
logging.debug("start_application: %s %s", application_name, application_create_data)

api/src/main/resources/plugins/base_creator.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import string
3838
import collections
3939
import subprocess
40-
import os
4140
import hbase_descriptor
4241
import opentsdb_descriptor
4342
from deployer_utils import HDFS
@@ -235,10 +234,6 @@ def destroy_components(self, application_name, create_data):
235234
for single_component_data in create_data:
236235
self._destroy_optional_descriptors(single_component_data['descriptors'])
237236
self.destroy_component(application_name, single_component_data)
238-
local_path = '/opt/%s/%s/' % (self._namespace, application_name)
239-
if os.path.isdir(local_path):
240-
os.rmdir(local_path)
241-
self._hdfs_client.remove('/user/%s' % application_name, recursive=False)
242237
return None
243238

244239
def start_components(self, application_name, start_data):
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""
2+
Name: jupyter.py
3+
Purpose: Installs a jupyter notebook
4+
Author: PNDA team
5+
6+
Created: 03/10/2016
7+
8+
Copyright (c) 2016 Cisco and/or its affiliates.
9+
10+
This software is licensed to you under the terms of the Apache License, Version 2.0 (the "License").
11+
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
12+
13+
The code, technical concepts, and all information contained herein, are the property of Cisco Technology, Inc.
14+
and/or its affiliated entities, under various laws including copyright, international treaties, patent,
15+
and/or contract. Any use of the material herein must be in accordance with the terms of the License.
16+
All rights not expressly granted by the License are reserved.
17+
18+
Unless required by applicable law or agreed to separately in writing, software distributed under the
19+
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
20+
either express or implied.
21+
"""
22+
23+
# pylint: disable=C0103
24+
25+
import json
26+
import os
27+
import logging
28+
29+
import deployer_utils
30+
from plugins.base_creator import Creator
31+
32+
33+
class JupyterCreator(Creator):
34+
35+
def validate_component(self, component):
36+
errors = []
37+
file_list = component['component_detail']
38+
for file_name in file_list:
39+
if file_name.endswith(r'.ipynb'):
40+
notebook_found = True
41+
42+
if not notebook_found:
43+
errors.append('missing ipynb file')
44+
45+
return errors
46+
47+
def get_component_type(self):
48+
return 'jupyter'
49+
50+
def destroy_component(self, application_name, create_data):
51+
logging.debug("destroy_component: %s %s", application_name, json.dumps(create_data))
52+
key_file = self._environment['cluster_private_key']
53+
root_user = self._environment['cluster_root_user']
54+
target_host = self._environment['jupyter_host']
55+
deployer_utils.exec_ssh(target_host, root_user, key_file, create_data['delete_commands'])
56+
57+
def start_component(self, application_name, create_data):
58+
logging.debug("start_component (nothing to do for jupyter): %s %s", application_name, json.dumps(create_data))
59+
60+
def stop_component(self, application_name, create_data):
61+
logging.debug("stop_component (nothing to do for jupyter): %s %s", application_name, json.dumps(create_data))
62+
63+
def create_component(self, staged_component_path, application_name, component, properties):
64+
logging.debug("create_component: %s %s %s", application_name, json.dumps(component), properties)
65+
66+
key_file = self._environment['cluster_private_key']
67+
root_user = self._environment['cluster_root_user']
68+
target_host = self._environment['jupyter_host']
69+
delete_commands = []
70+
71+
mkdircommands = []
72+
remote_component_tmp_path = '%s/%s/%s' % ('/tmp/%s' % self._namespace, application_name, component['component_name'])
73+
mkdircommands.append('mkdir -p %s' % remote_component_tmp_path)
74+
deployer_utils.exec_ssh(target_host, root_user, key_file, mkdircommands)
75+
76+
file_list = component['component_detail']
77+
for file_name in file_list:
78+
if file_name.endswith(r'.ipynb'):
79+
self._fill_properties('%s/%s' % (staged_component_path, file_name), properties)
80+
logging.debug('Copying %s/* to %s:%s', staged_component_path, target_host, remote_component_tmp_path)
81+
os.system("scp -i %s -o StrictHostKeyChecking=no %s/%s %s@%s:%s" %
82+
(key_file, staged_component_path, file_name, root_user, target_host, remote_component_tmp_path))
83+
84+
remote_component_install_path = '%s/%s_%s' % (self._environment['jupyter_notebook_directory'], application_name, file_name)
85+
deployer_utils.exec_ssh(
86+
target_host, root_user, key_file,
87+
['sudo mv %s %s' % (remote_component_tmp_path + '/*.ipynb', remote_component_install_path)])
88+
delete_commands.append('sudo rm -rf %s\n' % remote_component_install_path)
89+
90+
logging.debug("uninstall commands: %s", delete_commands)
91+
return {'delete_commands': delete_commands}

api/src/main/resources/test_application_creator.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,13 +338,15 @@ def test_invalid_package(self):
338338
creator.validate_package('test-package-1.0.2', {"package_name": "test-package-1.0.2", "component_types": {}})
339339

340340
# pylint: disable=unused-argument
341+
@patch('deployer_utils.HDFS')
341342
@patch('deployer_utils.exec_ssh')
342343
@patch('requests.put')
343344
@patch('os.path.isdir')
344345
@patch('os.rmdir')
345-
def test_destroy_application(self, rmdir_mock, isdir_mock, put_mock, exec_ssh_mock):
346+
def test_destroy_application(self, rmdir_mock, isdir_mock, put_mock, exec_ssh_mock, hdfs_client_mock):
346347
isdir_mock.return_value = True
347348
creator = ApplicationCreator(self.config, self.environment, self.service)
349+
creator._hdfs_client = hdfs_client_mock
348350
creator.destroy_application('name', self.create_data)
349351
print exec_ssh_mock.call_args_list
350352
exec_ssh_mock.assert_any_call('localhost', 'root_user', 'keyfile.pem', [

api/src/main/resources/test_deployer_manager.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ def test_get_environment(self):
584584
repository = Mock()
585585
package_registrar = Mock()
586586
application_registrar = Mock()
587-
environment = {"namespace": "some_namespace"}
587+
environment = {"namespace": "some_namespace", 'webhdfs_host': 'webhdfshost', 'webhdfs_port': 'webhdfsport'}
588588
config = {"deployer_thread_limit": 10}
589589

590590
dmgr = DeploymentManager(repository,
@@ -602,7 +602,7 @@ def test_list_packages(self):
602602
package_registrar = Mock()
603603
package_registrar.list_packages.return_value = expected_packages
604604
application_registrar = Mock()
605-
environment = {"namespace": "some_namespace"}
605+
environment = {"namespace": "some_namespace", 'webhdfs_host': 'webhdfshost', 'webhdfs_port': 'webhdfsport'}
606606
config = {"deployer_thread_limit": 10}
607607

608608
dmgr = DeploymentManager(repository,
@@ -633,7 +633,7 @@ def test_list_repository(self):
633633

634634
package_registrar = Mock()
635635
application_registrar = Mock()
636-
environment = {"namespace": "some_namespace"}
636+
environment = {"namespace": "some_namespace", 'webhdfs_host': 'webhdfshost', 'webhdfs_port': 'webhdfsport'}
637637
config = {"deployer_thread_limit": 10}
638638

639639
dmgr = DeploymentManager(repository,
@@ -650,7 +650,7 @@ def test_get_unknown_package_info(self):
650650
package_registrar.get_package_deploy_status.return_value = None
651651
package_registrar.package_exists.return_value = False
652652
application_registrar = Mock()
653-
environment = {"namespace": "some_namespace"}
653+
environment = {"namespace": "some_namespace", 'webhdfs_host': 'webhdfshost', 'webhdfs_port': 'webhdfsport'}
654654
config = {"deployer_thread_limit": 10}
655655

656656
dmgr = DeploymentManager(repository,
@@ -673,7 +673,7 @@ def test_list_package_applications(self):
673673
package_registrar = Mock()
674674
application_registrar = Mock()
675675
application_registrar.list_applications_for_package.return_value = expected_applications
676-
environment = {"namespace": "some_namespace"}
676+
environment = {"namespace": "some_namespace", 'webhdfs_host': 'webhdfshost', 'webhdfs_port': 'webhdfsport'}
677677
config = {"deployer_thread_limit": 10}
678678

679679
dmgr = DeploymentManager(repository,
@@ -691,7 +691,7 @@ def test_list_applications(self):
691691
package_registrar = Mock()
692692
application_registrar = Mock()
693693
application_registrar.list_applications.return_value = expected_applications
694-
environment = {"namespace": "some_namespace"}
694+
environment = {"namespace": "some_namespace", 'webhdfs_host': 'webhdfshost', 'webhdfs_port': 'webhdfsport'}
695695
config = {"deployer_thread_limit": 10}
696696

697697
dmgr = DeploymentManager(repository,
@@ -713,7 +713,7 @@ def test_application_in_progress(self):
713713
'package_name': 'package_name',
714714
'status': ApplicationState.STARTING,
715715
'information': None}
716-
environment = {"namespace": "some_namespace"}
716+
environment = {"namespace": "some_namespace", 'webhdfs_host': 'webhdfshost', 'webhdfs_port': 'webhdfsport'}
717717
config = {"deployer_thread_limit": 10}
718718

719719
dmgr = DeploymentManager(repository,
@@ -728,7 +728,7 @@ def test_package_in_progress(self):
728728
repository = Mock()
729729
package_registrar = Mock()
730730
application_registrar = Mock()
731-
environment = {"namespace": "some_namespace"}
731+
environment = {"namespace": "some_namespace", 'webhdfs_host': 'webhdfshost', 'webhdfs_port': 'webhdfsport'}
732732
config = {"deployer_thread_limit": 10}
733733

734734
class DeploymentManagerTester(DeploymentManager):
@@ -750,7 +750,7 @@ def test_package_not_exists(self):
750750
package_registrar.get_package_deploy_status.return_value = None
751751
package_registrar.package_exists.return_value = False
752752
application_registrar = Mock()
753-
environment = {"namespace": "some_namespace"}
753+
environment = {"namespace": "some_namespace", 'webhdfs_host': 'webhdfshost', 'webhdfs_port': 'webhdfsport'}
754754
config = {"deployer_thread_limit": 10}
755755
dmgr = DeploymentManager(repository,
756756
package_registrar,
@@ -775,7 +775,7 @@ def test_get_application_detail(self, app_mock):
775775
'package_name': 'package_name',
776776
'status': ApplicationState.STARTED,
777777
'information': None}
778-
environment = {"namespace": "some_namespace"}
778+
environment = {"namespace": "some_namespace", 'webhdfs_host': 'webhdfshost', 'webhdfs_port': 'webhdfsport'}
779779
config = {"deployer_thread_limit": 10}
780780

781781
dmgr = DeploymentManager(repository,
@@ -801,7 +801,7 @@ def test_fail_get_detail(self, app_mock):
801801
'package_name': 'package_name',
802802
'status': ApplicationState.NOTCREATED,
803803
'information': None}
804-
environment = {"namespace": "some_namespace"}
804+
environment = {"namespace": "some_namespace", 'webhdfs_host': 'webhdfshost', 'webhdfs_port': 'webhdfsport'}
805805
config = {"deployer_thread_limit": 10}
806806

807807
dmgr = DeploymentManager(repository,

0 commit comments

Comments
 (0)