dtk-client 0.9.1 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/Gemfile +1 -3
- data/README.md +2 -121
- data/Rakefile +44 -0
- data/bin/dtk +10 -88
- data/dtk-client.gemspec +21 -44
- data/examples/simple/dtk.module.yaml +32 -0
- data/{lib/git-logs/git.log → examples/simple/test/README.md} +0 -0
- data/examples/spark/dtk.module.yaml +120 -0
- data/examples/with_repo_content/deploy/puppet/manifests/hostname.pp +54 -0
- data/examples/with_repo_content/dtk.module.yaml +49 -0
- data/examples/with_repo_content/test/README.txt +0 -0
- data/features/dtk.feature +8 -0
- data/features/step_definitions/dtk_steps.rb +6 -0
- data/features/support/env.rb +15 -0
- data/lib/cli/command/mixin.rb +101 -0
- data/lib/cli/command/module/clone.rb +42 -0
- data/lib/cli/command/module/install.rb +52 -0
- data/lib/cli/command/module/list.rb +31 -0
- data/lib/cli/command/module/list_assemblies.rb +39 -0
- data/lib/cli/command/module/push.rb +34 -0
- data/lib/cli/command/module/uninstall.rb +46 -0
- data/lib/cli/command/module.rb +33 -0
- data/lib/cli/command/options.rb +33 -0
- data/lib/cli/command/service/cancel_task.rb +33 -0
- data/lib/cli/command/service/converge.rb +37 -0
- data/lib/{parser/adapters/thor/common_option_defs.rb → cli/command/service/create_workspace.rb} +13 -17
- data/lib/cli/command/service/destroy.rb +47 -0
- data/lib/cli/command/service/edit.rb +47 -0
- data/lib/cli/command/service/exec.rb +42 -0
- data/lib/cli/command/service/exec_sync.rb +53 -0
- data/lib/cli/command/service/list.rb +30 -0
- data/lib/cli/command/service/list_actions.rb +39 -0
- data/lib/cli/command/service/list_attributes.rb +44 -0
- data/lib/cli/command/service/list_component_links.rb +33 -0
- data/lib/cli/command/service/list_components.rb +39 -0
- data/lib/cli/command/service/list_dependent_modules.rb +33 -0
- data/lib/cli/command/service/list_nodes.rb +33 -0
- data/lib/cli/command/service/list_violations.rb +33 -0
- data/lib/cli/command/service/pull.rb +32 -0
- data/lib/cli/command/service/push.rb +37 -0
- data/lib/{shell/parse_monkey_patch.rb → cli/command/service/set_default_target.rb} +9 -17
- data/lib/cli/command/service/set_required_attributes.rb +32 -0
- data/lib/cli/command/service/ssh.rb +42 -0
- data/lib/cli/command/service/stage.rb +55 -0
- data/lib/cli/command/service/start.rb +33 -0
- data/lib/{shell/context_aux.rb → cli/command/service/stop.rb} +10 -23
- data/lib/cli/command/service/task_status.rb +39 -0
- data/lib/cli/command/service.rb +55 -0
- data/lib/{commands.rb → cli/command/subcommand.rb} +22 -25
- data/lib/{bundler_monkey_patch.rb → cli/command/token/arg.rb} +6 -6
- data/lib/cli/command/token/class_mixin.rb +96 -0
- data/lib/cli/command/token/flag.rb +42 -0
- data/lib/{execute/command/rest_call.rb → cli/command/token/mixin.rb} +23 -14
- data/lib/cli/command/token/switch.rb +35 -0
- data/lib/cli/command/token.rb +76 -0
- data/lib/cli/command.rb +46 -0
- data/lib/cli/context/attributes.rb +50 -0
- data/lib/cli/context/type/module.rb +34 -0
- data/lib/{commands/thor/state_change.rb → cli/context/type/service.rb} +11 -5
- data/lib/cli/context/type/top.rb +32 -0
- data/lib/cli/context/type.rb +42 -0
- data/lib/cli/context.rb +174 -0
- data/lib/cli/directory_parser/file_system.rb +105 -0
- data/lib/{execute/command.rb → cli/directory_parser.rb} +14 -17
- data/lib/{execute.rb → cli/file_obj.rb} +13 -9
- data/lib/cli/processor/plugin/gli.rb +70 -0
- data/lib/cli/processor.rb +60 -0
- data/lib/cli/runner/dtkn_access.rb +75 -0
- data/lib/cli/runner.rb +58 -0
- data/lib/cli/version.rb +8 -0
- data/lib/{config → client/config}/cacert.pem +0 -0
- data/lib/client/config/default.conf +20 -0
- data/lib/client/config.rb +106 -0
- data/lib/client/configurator.rb +182 -0
- data/lib/client/conn.rb +197 -0
- data/lib/client/content_generator.rb +127 -0
- data/lib/client/error/subclasses.rb +105 -0
- data/lib/client/error.rb +98 -0
- data/lib/client/git_repo/adapter/git_gem/error_handler.rb +70 -0
- data/lib/client/git_repo/adapter/git_gem.rb +179 -0
- data/lib/client/git_repo.rb +122 -0
- data/lib/client/logger.rb +136 -0
- data/lib/client/operation/account.rb +66 -0
- data/lib/client/operation/client_module_dir/git_repo.rb +286 -0
- data/lib/client/operation/client_module_dir.rb +138 -0
- data/lib/client/operation/module/clone_module.rb +52 -0
- data/lib/client/operation/module/install/common_module.rb +58 -0
- data/lib/client/operation/module/install/external_module.rb +122 -0
- data/lib/client/operation/module/install.rb +91 -0
- data/lib/client/operation/module/install_from_catalog.rb +76 -0
- data/lib/client/operation/module/list.rb +34 -0
- data/lib/client/operation/module/list_assemblies.rb +35 -0
- data/lib/client/operation/module/push.rb +62 -0
- data/lib/client/operation/module/uninstall.rb +44 -0
- data/lib/client/operation/module.rb +58 -0
- data/lib/{commands/common/thor/reparse.rb → client/operation/module_service_common.rb} +27 -16
- data/lib/client/operation/service/cancel_task.rb +29 -0
- data/lib/client/operation/service/commit_and_push.rb +128 -0
- data/lib/client/operation/service/converge.rb +50 -0
- data/lib/{util/common_util.rb → client/operation/service/create_workspace.rb} +13 -13
- data/lib/client/operation/service/destroy.rb +42 -0
- data/lib/client/operation/service/edit.rb +54 -0
- data/lib/client/operation/service/exec.rb +73 -0
- data/lib/client/operation/service/list.rb +32 -0
- data/lib/client/operation/service/list_actions.rb +34 -0
- data/lib/{commands/thor/dependency.rb → client/operation/service/list_attributes.rb} +16 -12
- data/lib/client/operation/service/list_component_links.rb +29 -0
- data/lib/{commands/common/thor/pull_clone_changes.rb → client/operation/service/list_components.rb} +13 -7
- data/lib/client/operation/service/list_dependent_modules.rb +29 -0
- data/lib/client/operation/service/list_nodes.rb +29 -0
- data/lib/{commands/thor/project.rb → client/operation/service/list_violations.rb} +8 -13
- data/lib/client/operation/service/pull.rb +37 -0
- data/lib/client/operation/service/set_default_target.rb +31 -0
- data/lib/client/operation/service/set_required_attributes.rb +41 -0
- data/lib/client/operation/service/ssh.rb +118 -0
- data/lib/client/operation/service/stage.rb +54 -0
- data/lib/client/operation/service/start.rb +29 -0
- data/lib/client/operation/service/stop.rb +30 -0
- data/lib/{task_status → client/operation/service/task_status}/refresh_mode.rb +15 -25
- data/lib/{task_status → client/operation/service/task_status}/snapshot_mode.rb +4 -5
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/format.rb +1 -1
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/result/action.rb +1 -1
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/result/components.rb +1 -1
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/result/node_level.rb +1 -1
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/result.rb +4 -4
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/steps/action.rb +1 -1
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/steps/components.rb +1 -1
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/steps/node_level.rb +1 -1
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task/steps.rb +4 -4
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/hierarchical_task.rb +3 -3
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/no_results.rb +1 -1
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/render.rb +1 -1
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/stage/render.rb +1 -1
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/stage.rb +3 -3
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/task_end.rb +1 -1
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element/task_start.rb +1 -1
- data/lib/{task_status → client/operation/service/task_status}/stream_mode/element.rb +13 -13
- data/lib/{task_status → client/operation/service/task_status}/stream_mode.rb +5 -9
- data/lib/client/operation/service/task_status.rb +77 -0
- data/lib/client/operation/service.rb +54 -0
- data/lib/client/operation.rb +67 -0
- data/lib/client/operation_args.rb +40 -0
- data/lib/{execute/execute_context/result_store.rb → client/render/view/simple.rb} +15 -14
- data/lib/client/render/view/table/processor.rb +248 -0
- data/lib/client/render/view/table.rb +75 -0
- data/lib/client/render.rb +113 -0
- data/lib/client/response/error_handler.rb +97 -0
- data/lib/client/response/render_helper.rb +78 -0
- data/lib/client/response/subclasses.rb +62 -0
- data/lib/client/response.rb +83 -0
- data/lib/client/session.rb +62 -0
- data/lib/client/util/auxiliary.rb +34 -0
- data/lib/client/util/console.rb +81 -0
- data/lib/client/util/disk_cacher.rb +66 -0
- data/lib/client/util/dtk_path.rb +28 -0
- data/lib/{search_hash.rb → client/util/hash_with_optional_keys.rb} +29 -21
- data/lib/client/util/interactive_wizard.rb +84 -0
- data/lib/client/util/module_ref.rb +92 -0
- data/lib/client/util/os_util/print.rb +121 -0
- data/lib/client/util/os_util.rb +122 -0
- data/lib/{commands/thor/utils.rb → client/util/post_body.rb} +1 -1
- data/lib/{execute/error_usage.rb → client/util/query_string_hash.rb} +2 -2
- data/lib/client/util/remote_dependency.rb +67 -0
- data/lib/client/util/ssh_util.rb +89 -0
- data/lib/client/util/validation.rb +28 -0
- data/lib/client/util.rb +18 -0
- data/lib/{util/permission_util.rb → dtk_cli.rb} +10 -9
- data/lib/dtk_client.rb +18 -14
- data/test/default_test.rb +14 -0
- data/test/test_helper.rb +9 -0
- metadata +196 -307
- data/Gemfile_dev +0 -13
- data/bin/dtk-execute +0 -32
- data/bin/dtk-shell +0 -31
- data/lib/auxiliary.rb +0 -61
- data/lib/client.rb +0 -58
- data/lib/command_helper.rb +0 -33
- data/lib/command_helpers/git_repo/merge.rb +0 -153
- data/lib/command_helpers/git_repo.rb +0 -589
- data/lib/command_helpers/jenkins_client/config_xml.rb +0 -288
- data/lib/command_helpers/jenkins_client.rb +0 -106
- data/lib/command_helpers/service_importer.rb +0 -251
- data/lib/command_helpers/service_link.rb +0 -33
- data/lib/command_helpers/test_module_creator.rb +0 -69
- data/lib/command_helpers/test_module_templates/dtk.model.yaml.eruby +0 -10
- data/lib/command_helpers/test_module_templates/spec_helper.rb.eruby +0 -10
- data/lib/command_helpers/test_module_templates/temp_component_spec.rb.eruby +0 -5
- data/lib/commands/common/thor/access_control.rb +0 -133
- data/lib/commands/common/thor/action_result_handler.rb +0 -74
- data/lib/commands/common/thor/assembly_template.rb +0 -92
- data/lib/commands/common/thor/assembly_workspace.rb +0 -1638
- data/lib/commands/common/thor/base_command_helper.rb +0 -59
- data/lib/commands/common/thor/clone.rb +0 -82
- data/lib/commands/common/thor/common.rb +0 -88
- data/lib/commands/common/thor/common_base.rb +0 -49
- data/lib/commands/common/thor/create_target.rb +0 -70
- data/lib/commands/common/thor/edit.rb +0 -255
- data/lib/commands/common/thor/inventory_parser.rb +0 -98
- data/lib/commands/common/thor/list_diffs.rb +0 -128
- data/lib/commands/common/thor/module/import.rb +0 -215
- data/lib/commands/common/thor/module.rb +0 -1011
- data/lib/commands/common/thor/node.rb +0 -53
- data/lib/commands/common/thor/poller.rb +0 -65
- data/lib/commands/common/thor/pull_from_remote.rb +0 -152
- data/lib/commands/common/thor/puppet_forge.rb +0 -72
- data/lib/commands/common/thor/purge_clone.rb +0 -101
- data/lib/commands/common/thor/push_clone_changes.rb +0 -162
- data/lib/commands/common/thor/push_to_remote.rb +0 -94
- data/lib/commands/common/thor/remotes.rb +0 -71
- data/lib/commands/common/thor/set_required_attributes.rb +0 -46
- data/lib/commands/thor/account.rb +0 -239
- data/lib/commands/thor/assembly.rb +0 -361
- data/lib/commands/thor/attribute.rb +0 -79
- data/lib/commands/thor/component.rb +0 -70
- data/lib/commands/thor/component_module.rb +0 -501
- data/lib/commands/thor/component_template.rb +0 -174
- data/lib/commands/thor/developer.rb +0 -144
- data/lib/commands/thor/dtk.rb +0 -152
- data/lib/commands/thor/library.rb +0 -125
- data/lib/commands/thor/node.rb +0 -504
- data/lib/commands/thor/node_group.rb +0 -203
- data/lib/commands/thor/node_template.rb +0 -94
- data/lib/commands/thor/provider.rb +0 -233
- data/lib/commands/thor/remotes.rb +0 -49
- data/lib/commands/thor/service.rb +0 -932
- data/lib/commands/thor/service_module.rb +0 -900
- data/lib/commands/thor/target.rb +0 -250
- data/lib/commands/thor/task.rb +0 -116
- data/lib/commands/thor/test_module.rb +0 -310
- data/lib/commands/thor/workspace.rb +0 -698
- data/lib/config/client.conf.header +0 -20
- data/lib/config/configuration.rb +0 -99
- data/lib/config/default.conf +0 -16
- data/lib/config/disk_cacher.rb +0 -80
- data/lib/configurator.rb +0 -176
- data/lib/context_router.rb +0 -44
- data/lib/core.rb +0 -489
- data/lib/domain/git_adapter.rb +0 -412
- data/lib/domain/git_error_handler.rb +0 -64
- data/lib/domain/response/error_handler.rb +0 -86
- data/lib/domain/response.rb +0 -285
- data/lib/dtk-client/version.rb +0 -20
- data/lib/dtk_constants.rb +0 -40
- data/lib/dtk_error.rb +0 -114
- data/lib/dtk_logger.rb +0 -113
- data/lib/error.rb +0 -85
- data/lib/execute/cli_pure/cli_rerouter.rb +0 -102
- data/lib/execute/command/api_call/map.rb +0 -60
- data/lib/execute/command/api_call/service.rb +0 -91
- data/lib/execute/command/api_call/translation_term.rb +0 -119
- data/lib/execute/command/api_call.rb +0 -60
- data/lib/execute/command_processor/rest_call.rb +0 -59
- data/lib/execute/command_processor.rb +0 -30
- data/lib/execute/execute_context.rb +0 -86
- data/lib/execute/script/add_tenant.rb +0 -121
- data/lib/execute/script.rb +0 -64
- data/lib/parser/adapters/option_parser.rb +0 -70
- data/lib/parser/adapters/thor.rb +0 -555
- data/lib/require_first.rb +0 -104
- data/lib/shell/context.rb +0 -1064
- data/lib/shell/domain/active_context.rb +0 -186
- data/lib/shell/domain/context_entity.rb +0 -89
- data/lib/shell/domain/context_params.rb +0 -223
- data/lib/shell/domain/override_tasks.rb +0 -88
- data/lib/shell/domain/shadow_entity.rb +0 -76
- data/lib/shell/header_shell.rb +0 -44
- data/lib/shell/help_monkey_patch.rb +0 -283
- data/lib/shell/interactive_wizard.rb +0 -256
- data/lib/shell/message_queue.rb +0 -63
- data/lib/shell/status_monitor.rb +0 -124
- data/lib/shell.rb +0 -261
- data/lib/task_status.rb +0 -83
- data/lib/util/console.rb +0 -235
- data/lib/util/dtk_puppet.rb +0 -65
- data/lib/util/module_util.rb +0 -66
- data/lib/util/os_util.rb +0 -385
- data/lib/util/remote_dependency_util.rb +0 -84
- data/lib/util/ssh_util.rb +0 -94
- data/lib/view_processor/augmented_simple_list.rb +0 -44
- data/lib/view_processor/hash_pretty_print.rb +0 -123
- data/lib/view_processor/simple_list.rb +0 -156
- data/lib/view_processor/table_print.rb +0 -309
- data/lib/view_processor.rb +0 -129
- data/puppet/manifests/init.pp +0 -72
- data/puppet/manifests/params.pp +0 -16
- data/puppet/r8meta.puppet.yml +0 -35
- data/puppet/templates/bash_profile.erb +0 -2
- data/puppet/templates/client.conf.erb +0 -1
- data/puppet/templates/dtkclient.erb +0 -2
- data/spec/component_module_spec.rb +0 -34
- data/spec/dependency_spec.rb +0 -6
- data/spec/dtk_shell_spec.rb +0 -13
- data/spec/dtk_spec.rb +0 -33
- data/spec/lib/spec_helper.rb +0 -10
- data/spec/lib/spec_thor.rb +0 -108
- data/spec/node_template_spec.rb +0 -24
- data/spec/project_spec.rb +0 -6
- data/spec/repo_spec.rb +0 -7
- data/spec/response_spec.rb +0 -52
- data/spec/service_module_spec.rb +0 -38
- data/spec/service_spec.rb +0 -50
- data/spec/state_change_spec.rb +0 -7
- data/spec/table_print_spec.rb +0 -48
- data/spec/target_spec.rb +0 -57
- data/spec/task_spec.rb +0 -28
- data/views/assembly/augmented_simple_list.rb +0 -12
- data/views/assembly_template/augmented_simple_list.rb +0 -12
- data/views/list_task/augmented_simple_list.rb +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63474c8dc3c49c71f705cc21ff398b64f72adac4
|
4
|
+
data.tar.gz: d54921f4093a817ecfc2d8f58766ab34e6b949af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50369f8f5f07e47c8edbb8c2eb257330dd4a0b02955fe507c8e958542ae3ccd85c65e33d49bb92679663f6efc69ff997cfcc052bed223dcda021fe713a0391ff
|
7
|
+
data.tar.gz: 5eeaa8383df1bc7e445c1a29ac1af5f6236cbe97929abc06706d16ab53e97ffc6b1d9d663563c45cfd8e279cd41f80151796f41dcc54a334fe43e79be0e246ef
|
data/.gitignore
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,121 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
#### Description
|
6
|
-
|
7
|
-
|
8
|
-
DTK Client is a Ruby based CLI interface for communication with the DTK Server.
|
9
|
-
It's main purpose is to provide an easy to use interface for importing modules, browsing modules repository and deploying assemblies and topologies.
|
10
|
-
|
11
|
-
---
|
12
|
-
#### Sytstem requirements
|
13
|
-
|
14
|
-
- Ruby 1.9.3
|
15
|
-
- Unix OS
|
16
|
-
|
17
|
-
---
|
18
|
-
#### Installation
|
19
|
-
|
20
|
-
For DTK Client to work, following steps have to be done:
|
21
|
-
|
22
|
-
- Git User set up
|
23
|
-
- RSA Keys Generated
|
24
|
-
|
25
|
-
To install DTK Client gem, execute:
|
26
|
-
|
27
|
-
`gem install dtk-client`
|
28
|
-
|
29
|
-
---
|
30
|
-
#### Initial setup
|
31
|
-
|
32
|
-
There are two ways for DTK Client to run
|
33
|
-
|
34
|
-
- via an interactive shell (<tt>dtk-shell</tt>)
|
35
|
-
- by executing DTK Client commands (ie. <tt>dtk service list</tt>)
|
36
|
-
|
37
|
-
If it is the first time that the DTK Client is being used (by either of the ways), following prompts will appear:
|
38
|
-
|
39
|
-
```
|
40
|
-
Please enter the DTK server address (example: instance.dtk.io)
|
41
|
-
Server address:
|
42
|
-
|
43
|
-
Please enter your DTK login details
|
44
|
-
Username:
|
45
|
-
Password:
|
46
|
-
|
47
|
-
```
|
48
|
-
After entering the correct data, following message will appear:
|
49
|
-
|
50
|
-
`SSH key 'dtk-client' added successfully!`
|
51
|
-
|
52
|
-
This means that the DTK Server has successfully registered DTK Client and the client is ready for use.
|
53
|
-
|
54
|
-
---
|
55
|
-
#### DTK Client configuration
|
56
|
-
|
57
|
-
All of the DTK Configuration, installed component and service modules as well as client logs are located in `~/dtk`.
|
58
|
-
|
59
|
-
DTK Client configuration options, such as development option, verbose calls to DTK Server, log options and Client user credentials, can be configured in `~/dtk/client.conf`:
|
60
|
-
|
61
|
-
```
|
62
|
-
debug_task_frequency=5 # assembly - frequency between requests (seconds)
|
63
|
-
auto_commit_changes=false # autocommit for modules
|
64
|
-
verbose_rest_calls=false # logging of REST calls
|
65
|
-
|
66
|
-
module_location=component_modules
|
67
|
-
service_location=service_modules
|
68
|
-
test_module_location=test_modules
|
69
|
-
backups_location=backups
|
70
|
-
|
71
|
-
|
72
|
-
server_port=80
|
73
|
-
secure_connection_server_port=443
|
74
|
-
secure_connection=true
|
75
|
-
server_host=instance.dtk.io
|
76
|
-
```
|
77
|
-
|
78
|
-
|
79
|
-
User credentials are located in `~/dtk/.connection`
|
80
|
-
|
81
|
-
Component and Service modules that are installed, or modules that are imported are located in `~/dtk/component_modules` and `~/dtk/service_modules/`
|
82
|
-
|
83
|
-
---
|
84
|
-
|
85
|
-
## Advanced features
|
86
|
-
#### Development mode
|
87
|
-
|
88
|
-
When using DTK Client in Development mode, gems from `Gemfile_dev` must be installed and used when running DTK Client or DTK Client Shell:
|
89
|
-
|
90
|
-
```
|
91
|
-
bundle install --gemfile Gemfile_dev
|
92
|
-
BUNDLE_GEMFILE=Gemfile_dev bundle exec ruby ./bin/dtk-shell
|
93
|
-
```
|
94
|
-
|
95
|
-
#### DTK Repoman
|
96
|
-
|
97
|
-
DTK Repoman is a Git based repository for publishing and installing component modules and service modules. DTK Repoman has it's own users, known as catalog users. The inital setup should register the DTK Client to the Public Catalog users.
|
98
|
-
|
99
|
-
Successfully registered DTK Client on DTK Repoman enables execution of commands such as:
|
100
|
-
|
101
|
-
`dtk service-module list --remote` - lists service moduels on remote visible to the catalog user
|
102
|
-
|
103
|
-
`dtk component-module install namespace/component-module-name` - install component module
|
104
|
-
|
105
|
-
Switching from public user to a commercial user can be done with `dtk account set-catalog-credentials`. This will initate a prompt for catalog username and password
|
106
|
-
|
107
|
-
## License
|
108
|
-
|
109
|
-
dtk-client is copyright (C) 2010-2016 dtk contributors
|
110
|
-
|
111
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
112
|
-
you may not use this work except in compliance with the License.
|
113
|
-
You may obtain a copy of the License in the [LICENSE](LICENSE) file, or at:
|
114
|
-
|
115
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
116
|
-
|
117
|
-
Unless required by applicable law or agreed to in writing, software
|
118
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
119
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
120
|
-
See the License for the specific language governing permissions and
|
121
|
-
limitations under the License.
|
1
|
+
# dtk-client2
|
2
|
+
DTK client
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rake/clean'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rubygems/package_task'
|
4
|
+
require 'rdoc/task'
|
5
|
+
require 'cucumber'
|
6
|
+
require 'cucumber/rake/task'
|
7
|
+
Rake::RDocTask.new do |rd|
|
8
|
+
rd.main = "README.rdoc"
|
9
|
+
rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
|
10
|
+
rd.title = 'Your application title'
|
11
|
+
end
|
12
|
+
|
13
|
+
spec = eval(File.read('dtk.gemspec'))
|
14
|
+
|
15
|
+
Gem::PackageTask.new(spec) do |pkg|
|
16
|
+
end
|
17
|
+
CUKE_RESULTS = 'results.html'
|
18
|
+
CLEAN << CUKE_RESULTS
|
19
|
+
desc 'Run features'
|
20
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
21
|
+
opts = "features --format html -o #{CUKE_RESULTS} --format progress -x"
|
22
|
+
opts += " --tags #{ENV['TAGS']}" if ENV['TAGS']
|
23
|
+
t.cucumber_opts = opts
|
24
|
+
t.fork = false
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Run features tagged as work-in-progress (@wip)'
|
28
|
+
Cucumber::Rake::Task.new('features:wip') do |t|
|
29
|
+
tag_opts = ' --tags ~@pending'
|
30
|
+
tag_opts = ' --tags @wip'
|
31
|
+
t.cucumber_opts = "features --format html -o #{CUKE_RESULTS} --format pretty -x -s#{tag_opts}"
|
32
|
+
t.fork = false
|
33
|
+
end
|
34
|
+
|
35
|
+
task :cucumber => :features
|
36
|
+
task 'cucumber:wip' => 'features:wip'
|
37
|
+
task :wip => 'features:wip'
|
38
|
+
require 'rake/testtask'
|
39
|
+
Rake::TestTask.new do |t|
|
40
|
+
t.libs << "test"
|
41
|
+
t.test_files = FileList['test/*_test.rb']
|
42
|
+
end
|
43
|
+
|
44
|
+
task :default => [:test,:features]
|
data/bin/dtk
CHANGED
@@ -1,92 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
-
# you may not use this file except in compliance with the License.
|
9
|
-
# You may obtain a copy of the License at
|
10
|
-
#
|
11
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
-
#
|
13
|
-
# Unless required by applicable law or agreed to in writing, software
|
14
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
-
# See the License for the specific language governing permissions and
|
17
|
-
# limitations under the License.
|
18
|
-
#
|
19
|
-
|
20
|
-
# GLOBAL IDENTIFIER
|
21
|
-
$shell_mode = false
|
22
|
-
|
23
|
-
require File.expand_path('../lib/client', File.dirname(__FILE__))
|
24
|
-
require File.expand_path('../lib/configurator', File.dirname(__FILE__))
|
25
|
-
require File.expand_path('../lib/parser/adapters/thor', File.dirname(__FILE__))
|
26
|
-
require File.expand_path('../lib/shell/context', File.dirname(__FILE__))
|
27
|
-
require File.expand_path('../lib/shell/domain/context_entity', File.dirname(__FILE__))
|
28
|
-
require File.expand_path('../lib/shell/domain/active_context', File.dirname(__FILE__))
|
29
|
-
require File.expand_path('../lib/shell/domain/context_params', File.dirname(__FILE__))
|
30
|
-
require File.expand_path('../lib/shell/domain/override_tasks', File.dirname(__FILE__))
|
31
|
-
require File.expand_path('../lib/shell/domain/shadow_entity', File.dirname(__FILE__))
|
32
|
-
require File.expand_path('../lib/commands/thor/account', File.dirname(__FILE__))
|
33
|
-
require File.expand_path('../lib/shell/parse_monkey_patch', File.dirname(__FILE__))
|
34
|
-
require File.expand_path('../lib/shell/help_monkey_patch', File.dirname(__FILE__))
|
35
|
-
require File.expand_path('../lib/execute/cli_pure/cli_rerouter', File.dirname(__FILE__))
|
36
|
-
|
37
|
-
paths = []
|
38
|
-
paths << File.expand_path('../lib/commands/thor/*.rb', File.dirname(__FILE__))
|
39
|
-
paths << File.expand_path('../lib/commands/common/thor/*.rb', File.dirname(__FILE__))
|
40
|
-
|
41
|
-
paths.each do |path|
|
42
|
-
Dir[path].each do |thor_class_file|
|
43
|
-
require thor_class_file
|
2
|
+
module DTK
|
3
|
+
require_relative '../lib/dtk_client'
|
4
|
+
module GlobalForDSL
|
5
|
+
Error = ::DTK::Client::Error
|
6
|
+
ErrorUsage = ::DTK::Client::Error::Usage
|
44
7
|
end
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
require 'shellwords'
|
50
|
-
require 'json'
|
51
|
-
|
52
|
-
$: << "/usr/lib/ruby/1.8/" #TODO: put in to get around path problem in rvm 1.9.2 environment
|
8
|
+
#dtk_dsl must be loaded after GlobalForDSL set
|
9
|
+
require 'dtk_dsl'
|
10
|
+
# lib/dtk_cli must be loaded after lib/client and lib/dsl
|
11
|
+
require_relative '../lib/dtk_cli'
|
53
12
|
|
54
|
-
|
55
|
-
::DTK::Client::Configurator.check_git
|
56
|
-
::DTK::Client::Configurator.create_missing_clone_dirs
|
57
|
-
|
58
|
-
|
59
|
-
# check if .add_direct_access file exists, if not then add direct access and create .add_direct_access file
|
60
|
-
resolve_direct_access(::DTK::Client::Configurator.check_direct_access, config_exists)
|
61
|
-
entries = []
|
62
|
-
|
63
|
-
if ARGV.size > 0
|
64
|
-
entries = ARGV
|
65
|
-
entries = DTK::Shell::Context.check_for_sym_link(entries)
|
66
|
-
entity_name = entries.shift
|
67
|
-
end
|
68
|
-
|
69
|
-
# special case for when no params are provided use help method
|
70
|
-
if (entity_name == 'help' || entity_name.nil?)
|
71
|
-
entity_name = 'dtk'
|
72
|
-
args = ['help']
|
73
|
-
else
|
74
|
-
args = entries
|
13
|
+
Client::CLI::Runner.run(ARGV)
|
75
14
|
end
|
76
|
-
|
77
|
-
context = DTK::Shell::Context.new(true)
|
78
|
-
|
79
|
-
begin
|
80
|
-
if ::DTK::CLIRerouter.is_candidate?(entity_name, args)
|
81
|
-
response_obj = ::DTK::CLIRerouter.new(entity_name, args).run()
|
82
|
-
puts response_obj.to_json
|
83
|
-
else
|
84
|
-
# default execution
|
85
|
-
entity_name, method_name, context_params, thor_options = context.get_dtk_command_parameters(entity_name, args)
|
86
|
-
top_level_execute(entity_name, method_name, context_params, thor_options, false)
|
87
|
-
end
|
88
|
-
rescue DTK::Client::DtkError => e
|
89
|
-
DtkLogger.instance.error(e.message, true)
|
90
|
-
rescue Exception => e
|
91
|
-
DtkLogger.instance.error_pp(e.message, e.backtrace)
|
92
|
-
end
|
data/dtk-client.gemspec
CHANGED
@@ -1,49 +1,26 @@
|
|
1
|
-
|
2
|
-
require File.expand_path('../lib/dtk-client/version', __FILE__)
|
1
|
+
require File.expand_path('../lib/cli/version', __FILE__)
|
3
2
|
|
4
|
-
Gem::Specification.new do |
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'dtk-client'
|
5
|
+
spec.version = DTK::Client::CLI::VERSION
|
6
|
+
spec.author = 'Reactor8'
|
7
|
+
spec.email = 'support@reactor8.com'
|
8
|
+
spec.description = %q{Command line tool to interact with a DTK Server and DTK Service Catalog.}
|
9
|
+
spec.summary = %q{DTK CLI client for DTK server interaction.}
|
10
|
+
spec.license = 'Apache 2.0'
|
11
|
+
spec.platform = Gem::Platform::RUBY
|
12
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 1.9.3')
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
gem.files += Dir.glob("lib/**/*")
|
15
|
-
gem.files += Dir.glob("puppet/**/*")
|
16
|
-
gem.files += Dir.glob("spec/**/*")
|
17
|
-
gem.files += Dir.glob("views/**/*")
|
14
|
+
spec.require_paths = ['lib']
|
15
|
+
spec.files = `git ls-files`.split("\n")
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
gem.name = "dtk-client"
|
22
|
-
gem.require_paths = ["lib"]
|
23
|
-
gem.version = DtkClient::VERSION
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
19
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
gem.add_dependency 'erubis','~> 2.7.0'
|
32
|
-
gem.add_dependency 'dtk-common-core','0.9.0'
|
33
|
-
gem.add_dependency 'git','1.2.9'
|
34
|
-
gem.add_dependency 'colorize','~> 0.5.8'
|
35
|
-
gem.add_dependency 'highline', '1.6.16'
|
36
|
-
gem.add_dependency 'awesome_print', '1.1.0'
|
37
|
-
|
38
|
-
# gem.add_dependency 'rb-readline', '0.5.0'
|
39
|
-
# gem.add_dependency 'activesupport','~> 3.2.12'
|
40
|
-
# gem.add_dependency 'i18n','0.6.1'
|
41
|
-
# gem.add_dependency 'puppet','~> 3.1.0'
|
42
|
-
# gem.add_dependency 'jenkins-client','~> 0.0.1'
|
43
|
-
# gem.add_dependency 'rspec','~> 2.12.0'
|
44
|
-
# gem.add_dependency 'awesome_print','~> 1.1.0'
|
45
|
-
# gem.add_dependency 'rdoc','= 3.12.1'l
|
46
|
-
# gem.add_development_dependency 'ruby-debug','>= 0.10.4'
|
47
|
-
# gem.add_development_dependency 'awesome_print','>= 1.1.0'
|
48
|
-
# gem.add_development_dependency 'rspec','~> 2.12.0'
|
20
|
+
spec.add_dependency 'dtk-common-core','0.10.0'
|
21
|
+
spec.add_dependency 'gli', '2.13.4'
|
22
|
+
spec.add_dependency 'highline', '1.7.8'
|
23
|
+
spec.add_dependency 'colorize', '0.7.7'
|
24
|
+
spec.add_dependency 'git', '1.2.9'
|
25
|
+
spec.add_dependency 'hirb', '0.7.3'
|
49
26
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
---
|
2
|
+
dsl_version: 1.0.0
|
3
|
+
module: rich/simple
|
4
|
+
version: 0.0.2
|
5
|
+
keywords: DTK-2554
|
6
|
+
description: Tests for DTK-2554
|
7
|
+
license: Apache 2.0
|
8
|
+
|
9
|
+
dependencies:
|
10
|
+
aws/ec2:
|
11
|
+
dtk/host: 1.0.1
|
12
|
+
assemblies:
|
13
|
+
simple:
|
14
|
+
description: Simple assembly for DTK-2554
|
15
|
+
attributes:
|
16
|
+
global_num: 5
|
17
|
+
nodes:
|
18
|
+
n1:
|
19
|
+
attributes:
|
20
|
+
image: amazon_hvm
|
21
|
+
size: micro
|
22
|
+
components:
|
23
|
+
- host::hostname:
|
24
|
+
attributes:
|
25
|
+
hostname: host1
|
26
|
+
workflows:
|
27
|
+
create:
|
28
|
+
subtasks:
|
29
|
+
- name: set hostname
|
30
|
+
components:
|
31
|
+
- host::hostname
|
32
|
+
|
File without changes
|
@@ -0,0 +1,120 @@
|
|
1
|
+
---
|
2
|
+
dsl_version: 1.0.0
|
3
|
+
module: rich/spark
|
4
|
+
keywords: spark, hdfs, zeppelin
|
5
|
+
description: Spark cluster
|
6
|
+
license: Apache 2.0
|
7
|
+
version: 0.1.2
|
8
|
+
|
9
|
+
dependencies:
|
10
|
+
- bigtop/bigtop_base
|
11
|
+
- bigtop/bigtop_multiservice
|
12
|
+
- bigtop-new/hadoop
|
13
|
+
- bigtop-new/spark
|
14
|
+
#- bigtop/zookeeper
|
15
|
+
- bigtop/zeppelin
|
16
|
+
assemblies:
|
17
|
+
cluster:
|
18
|
+
description: Spark cluster with Zeppelin on trusty
|
19
|
+
components:
|
20
|
+
- bigtop_multiservice
|
21
|
+
- hadoop::cluster:
|
22
|
+
component_links:
|
23
|
+
bigtop_multiservice: bigtop_multiservice
|
24
|
+
- spark::cluster:
|
25
|
+
component_links:
|
26
|
+
bigtop_multiservice: bigtop_multiservice
|
27
|
+
nodes:
|
28
|
+
master:
|
29
|
+
attributes:
|
30
|
+
image: trusty_hvm
|
31
|
+
size: medium
|
32
|
+
root_device_size: 30
|
33
|
+
components:
|
34
|
+
- bigtop_multiservice::hiera:
|
35
|
+
component_links:
|
36
|
+
bigtop_multiservice: bigtop_multiservice
|
37
|
+
- bigtop_base:
|
38
|
+
attributes:
|
39
|
+
with_maven: false
|
40
|
+
|
41
|
+
- hadoop::namenode
|
42
|
+
- hadoop::hdfs_directories
|
43
|
+
|
44
|
+
- spark::master:
|
45
|
+
attributes:
|
46
|
+
eventlog_enabled: true
|
47
|
+
component_links:
|
48
|
+
hadoop::hdfs_directories: master/hadoop::hdfs_directories
|
49
|
+
- spark::client
|
50
|
+
|
51
|
+
- zeppelin::server:
|
52
|
+
attributes:
|
53
|
+
install_mode: deb
|
54
|
+
component_links:
|
55
|
+
spark::master: master/spark::master
|
56
|
+
slaves:
|
57
|
+
attributes:
|
58
|
+
image: trusty_hvm
|
59
|
+
size: medium
|
60
|
+
cardinality: 2
|
61
|
+
type: group
|
62
|
+
components:
|
63
|
+
- bigtop_multiservice::hiera:
|
64
|
+
component_links:
|
65
|
+
bigtop_multiservice: bigtop_multiservice
|
66
|
+
- bigtop_base:
|
67
|
+
attributes:
|
68
|
+
with_maven: false
|
69
|
+
|
70
|
+
- hadoop::common_hdfs:
|
71
|
+
component_links:
|
72
|
+
hadoop::namenode: master/hadoop::namenode
|
73
|
+
- hadoop::datanode
|
74
|
+
|
75
|
+
- spark::common:
|
76
|
+
component_links:
|
77
|
+
spark::master: master/spark::master
|
78
|
+
- spark::worker
|
79
|
+
workflows:
|
80
|
+
create:
|
81
|
+
subtasks:
|
82
|
+
- name: bigtop_multiservice
|
83
|
+
components:
|
84
|
+
- bigtop_multiservice
|
85
|
+
- name: bigtop hiera
|
86
|
+
components:
|
87
|
+
- bigtop_multiservice::hiera
|
88
|
+
- name: bigtop_base
|
89
|
+
components:
|
90
|
+
- bigtop_base
|
91
|
+
|
92
|
+
- name: namenode
|
93
|
+
components:
|
94
|
+
- hadoop::namenode
|
95
|
+
- name: if needed leave safemode
|
96
|
+
actions:
|
97
|
+
- hadoop::namenode.leave_safemode
|
98
|
+
- name: namenode smoke test
|
99
|
+
actions:
|
100
|
+
- hadoop::namenode.smoke_test
|
101
|
+
- name: datanodes
|
102
|
+
ordered_components:
|
103
|
+
- hadoop::common_hdfs
|
104
|
+
- hadoop::datanode
|
105
|
+
- name: hdfs directories for spark
|
106
|
+
component:
|
107
|
+
- hadoop::hdfs_directories
|
108
|
+
|
109
|
+
- name: spark master and client
|
110
|
+
components:
|
111
|
+
- spark::master
|
112
|
+
- spark::client
|
113
|
+
- name: spark workers
|
114
|
+
ordered_components:
|
115
|
+
- spark::common
|
116
|
+
- spark::worker
|
117
|
+
|
118
|
+
- name: zeppelin server
|
119
|
+
components:
|
120
|
+
- zeppelin::server
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class host::hostname(
|
2
|
+
$hostname = undef,
|
3
|
+
$append_node_group_index = true
|
4
|
+
)
|
5
|
+
{
|
6
|
+
|
7
|
+
if $hostname == undef {
|
8
|
+
$base_name = $::dtk_assembly_node_base_name
|
9
|
+
} else {
|
10
|
+
$base_name = $hostname
|
11
|
+
}
|
12
|
+
|
13
|
+
if "${append_node_group_index}" == 'true' and $::dtk_assembly_node_type == 'node_group_member' and $::dtk_assembly_node_index != '' {
|
14
|
+
$new_hostname = "${base_name}-${::dtk_assembly_node_index}"
|
15
|
+
} else {
|
16
|
+
$new_hostname = $base_name
|
17
|
+
}
|
18
|
+
|
19
|
+
file { '/etc/hostname':
|
20
|
+
ensure => present,
|
21
|
+
content => "${new_hostname}\n"
|
22
|
+
}
|
23
|
+
|
24
|
+
exec { "hostname ${new_hostname}":
|
25
|
+
path => ['/bin']
|
26
|
+
}
|
27
|
+
|
28
|
+
host::hostname::set_hosts{ $new_hostname: }
|
29
|
+
}
|
30
|
+
|
31
|
+
define host::hostname::set_hosts() {
|
32
|
+
$new_hostname = $name
|
33
|
+
$new_hostname_with_domain = "${$new_hostname}.${::domain}"
|
34
|
+
|
35
|
+
if $::hostname != $new_hostname and $::hostname != $new_hostname_with_domain {
|
36
|
+
host { $::hostname:
|
37
|
+
ensure => 'absent'
|
38
|
+
}
|
39
|
+
}
|
40
|
+
if $::fqdn != $new_hostname and $::fqdn != $new_hostname_with_domain and $::hostname != $::fqdn {
|
41
|
+
host { $::fqdn:
|
42
|
+
ensure => 'absent'
|
43
|
+
}
|
44
|
+
}
|
45
|
+
# important for to make $new_hostname_with_domain and not $new_hostname primary
|
46
|
+
host { $new_hostname:
|
47
|
+
ensure => 'absent'
|
48
|
+
} ->
|
49
|
+
host { $new_hostname_with_domain:
|
50
|
+
ensure => 'present',
|
51
|
+
host_aliases => [$new_hostname],
|
52
|
+
ip => $::ipaddress_eth0
|
53
|
+
}
|
54
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
---
|
2
|
+
dsl_version: 1.0.0
|
3
|
+
module: rich/simple2
|
4
|
+
keywords: DTK-2554
|
5
|
+
description: Tests for DTK-2554
|
6
|
+
license: Apache 2.0
|
7
|
+
|
8
|
+
dependencies:
|
9
|
+
- aws/ec2
|
10
|
+
|
11
|
+
assemblies:
|
12
|
+
simple:
|
13
|
+
nodes:
|
14
|
+
n1:
|
15
|
+
attributes:
|
16
|
+
image: amazon_hvm
|
17
|
+
size: small
|
18
|
+
components:
|
19
|
+
- simple::hostname:
|
20
|
+
attributes:
|
21
|
+
hostname: host1
|
22
|
+
workflows:
|
23
|
+
create:
|
24
|
+
subtasks:
|
25
|
+
- name: set hostname
|
26
|
+
components:
|
27
|
+
- simple::hostname
|
28
|
+
providers:
|
29
|
+
puppet:
|
30
|
+
content:
|
31
|
+
- from: deploy/puppet
|
32
|
+
to: /etc/puppet/modules/rich
|
33
|
+
# For Puppet 'to:' can be omitted and default would be /etc/puppet/modules/<MODULENAME>
|
34
|
+
|
35
|
+
components:
|
36
|
+
hostname:
|
37
|
+
attributes:
|
38
|
+
hostname:
|
39
|
+
type: string
|
40
|
+
required: true
|
41
|
+
actions:
|
42
|
+
create:
|
43
|
+
puppet_class: simple::hostname
|
44
|
+
|
45
|
+
dtk_hostname:
|
46
|
+
description: Use dtk node name as host name
|
47
|
+
actions:
|
48
|
+
create:
|
49
|
+
puppet_class: simple::hostname
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'aruba/cucumber'
|
2
|
+
|
3
|
+
ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
|
4
|
+
LIB_DIR = File.join(File.expand_path(File.dirname(__FILE__)),'..','..','lib')
|
5
|
+
|
6
|
+
Before do
|
7
|
+
# Using "announce" causes massive warnings on 1.9.2
|
8
|
+
@puts = true
|
9
|
+
@original_rubylib = ENV['RUBYLIB']
|
10
|
+
ENV['RUBYLIB'] = LIB_DIR + File::PATH_SEPARATOR + ENV['RUBYLIB'].to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
After do
|
14
|
+
ENV['RUBYLIB'] = @original_rubylib
|
15
|
+
end
|