avmesos-cli 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- avmesos-cli-1.0.0/.gitignore +8 -0
- avmesos-cli-1.0.0/Makefile +37 -0
- avmesos-cli-1.0.0/PKG-INFO +84 -0
- avmesos-cli-1.0.0/README.md +73 -0
- avmesos-cli-1.0.0/avmesos/__init__.py +26 -0
- avmesos-cli-1.0.0/avmesos/cli/__init__.py +26 -0
- avmesos-cli-1.0.0/avmesos/cli/config.py +239 -0
- avmesos-cli-1.0.0/avmesos/cli/constants.py +25 -0
- avmesos-cli-1.0.0/avmesos/cli/docopt.py +89 -0
- avmesos-cli-1.0.0/avmesos/cli/exceptions.py +24 -0
- avmesos-cli-1.0.0/avmesos/cli/http.py +83 -0
- avmesos-cli-1.0.0/avmesos/cli/mesos-cli.py +155 -0
- avmesos-cli-1.0.0/avmesos/cli/mesos.py +891 -0
- avmesos-cli-1.0.0/avmesos/cli/plugins/__init__.py +22 -0
- avmesos-cli-1.0.0/avmesos/cli/plugins/agent/__init__.py +22 -0
- avmesos-cli-1.0.0/avmesos/cli/plugins/agent/main.py +82 -0
- avmesos-cli-1.0.0/avmesos/cli/plugins/base.py +179 -0
- avmesos-cli-1.0.0/avmesos/cli/plugins/config/__init__.py +22 -0
- avmesos-cli-1.0.0/avmesos/cli/plugins/config/main.py +97 -0
- avmesos-cli-1.0.0/avmesos/cli/plugins/framework/__init__.py +23 -0
- avmesos-cli-1.0.0/avmesos/cli/plugins/framework/main.py +110 -0
- avmesos-cli-1.0.0/avmesos/cli/plugins/task/__init__.py +22 -0
- avmesos-cli-1.0.0/avmesos/cli/plugins/task/main.py +167 -0
- avmesos-cli-1.0.0/avmesos/cli/settings.py +50 -0
- avmesos-cli-1.0.0/avmesos/cli/util.py +392 -0
- avmesos-cli-1.0.0/avmesos/exceptions.py +110 -0
- avmesos-cli-1.0.0/avmesos/http.py +397 -0
- avmesos-cli-1.0.0/avmesos/recordio.py +175 -0
- avmesos-cli-1.0.0/avmesos_cli.egg-info/PKG-INFO +84 -0
- avmesos-cli-1.0.0/avmesos_cli.egg-info/SOURCES.txt +36 -0
- avmesos-cli-1.0.0/avmesos_cli.egg-info/dependency_links.txt +1 -0
- avmesos-cli-1.0.0/avmesos_cli.egg-info/requires.txt +15 -0
- avmesos-cli-1.0.0/avmesos_cli.egg-info/top_level.txt +1 -0
- avmesos-cli-1.0.0/bin/mesos-cli +4 -0
- avmesos-cli-1.0.0/pip-requirements.txt +16 -0
- avmesos-cli-1.0.0/setup.cfg +4 -0
- avmesos-cli-1.0.0/setup.py +25 -0
- avmesos-cli-1.0.0/shell.nix +25 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#Dockerfile vars
|
|
2
|
+
|
|
3
|
+
#vars
|
|
4
|
+
|
|
5
|
+
.PHONY: help build bootstrap all
|
|
6
|
+
|
|
7
|
+
help:
|
|
8
|
+
@echo "Makefile arguments:"
|
|
9
|
+
@echo ""
|
|
10
|
+
@echo "Makefile commands:"
|
|
11
|
+
@echo "build"
|
|
12
|
+
@echo "all"
|
|
13
|
+
@echo "publish"
|
|
14
|
+
@echo ${TAG}
|
|
15
|
+
|
|
16
|
+
.DEFAULT_GOAL := all
|
|
17
|
+
|
|
18
|
+
build:
|
|
19
|
+
@echo ">>>> Build python module"
|
|
20
|
+
@python3 setup.py sdist bdist_wheel
|
|
21
|
+
|
|
22
|
+
upload:
|
|
23
|
+
@python3 -m twine upload --repository pypi dist/*
|
|
24
|
+
|
|
25
|
+
install:
|
|
26
|
+
@echo ">>>> Install python module"
|
|
27
|
+
@pip3 install .
|
|
28
|
+
|
|
29
|
+
install-dev:
|
|
30
|
+
@echo ">>>> Install python module development"
|
|
31
|
+
@pip3 install -e .
|
|
32
|
+
|
|
33
|
+
docs:
|
|
34
|
+
@echo ">>>> Build docs"
|
|
35
|
+
$(MAKE) -C $@
|
|
36
|
+
|
|
37
|
+
all: build
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: avmesos-cli
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Apache Mesos CLI
|
|
5
|
+
Home-page: https://www.aventer.biz/
|
|
6
|
+
Author: AVENTER UG (haftungsbeschraenkt)
|
|
7
|
+
Author-email: support@aventer.biz
|
|
8
|
+
License: Apache License 2.0
|
|
9
|
+
Requires-Python: >=3.6
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# Mesos CLI
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
Make sure you have python 3.6 or newer installed
|
|
17
|
+
on your system before you begin.
|
|
18
|
+
|
|
19
|
+
## How to install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
|
|
23
|
+
pip install avmesos-cli
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Setting up your configuration
|
|
28
|
+
|
|
29
|
+
In order to use this tool, you will need to create a
|
|
30
|
+
configuration file in your home directory under
|
|
31
|
+
`~/.mesos/config.toml`. A template for this config can be
|
|
32
|
+
seen below:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
# The `plugins` is an array listing the absolute paths of the
|
|
36
|
+
# plugins you want to add to the CLI.
|
|
37
|
+
plugins = [
|
|
38
|
+
"</absolute/path/to/plugin-1/directory>",
|
|
39
|
+
"</absolute/path/to/plugin-2/directory>"
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
# The `master` is a field that has to be composed of an
|
|
43
|
+
# `address` or `zookeeper` field, but not both. For example:
|
|
44
|
+
[master]
|
|
45
|
+
address = "10.10.0.30:5050"
|
|
46
|
+
principal = "username"
|
|
47
|
+
secret = "password"
|
|
48
|
+
|
|
49
|
+
[agent]
|
|
50
|
+
ssl = true
|
|
51
|
+
ssl_verify = false
|
|
52
|
+
principal = "username"
|
|
53
|
+
secret = "password"
|
|
54
|
+
timeout = 5
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
You can override the location of this configuration file using
|
|
58
|
+
the environment variable `MESOS_CLI_CONFIG`.
|
|
59
|
+
|
|
60
|
+
## How to use it
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
$ mesos-cli
|
|
64
|
+
|
|
65
|
+
Mesos CLI
|
|
66
|
+
|
|
67
|
+
Usage:
|
|
68
|
+
mesos (-h | --help)
|
|
69
|
+
mesos --version
|
|
70
|
+
mesos <command> [<args>...]
|
|
71
|
+
|
|
72
|
+
Options:
|
|
73
|
+
-h --help Show this screen.
|
|
74
|
+
--version Show version info.
|
|
75
|
+
|
|
76
|
+
Commands:
|
|
77
|
+
agent Interacts with the Mesos agents
|
|
78
|
+
config Interacts with the Mesos CLI configuration file
|
|
79
|
+
framework Interacts with the Mesos Frameworks
|
|
80
|
+
task Interacts with the tasks running in a Mesos cluster
|
|
81
|
+
|
|
82
|
+
See 'mesos help <command>' for more information on a specific command.
|
|
83
|
+
|
|
84
|
+
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Mesos CLI
|
|
2
|
+
|
|
3
|
+
## Prerequisites
|
|
4
|
+
|
|
5
|
+
Make sure you have python 3.6 or newer installed
|
|
6
|
+
on your system before you begin.
|
|
7
|
+
|
|
8
|
+
## How to install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
|
|
12
|
+
pip install avmesos-cli
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Setting up your configuration
|
|
17
|
+
|
|
18
|
+
In order to use this tool, you will need to create a
|
|
19
|
+
configuration file in your home directory under
|
|
20
|
+
`~/.mesos/config.toml`. A template for this config can be
|
|
21
|
+
seen below:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
# The `plugins` is an array listing the absolute paths of the
|
|
25
|
+
# plugins you want to add to the CLI.
|
|
26
|
+
plugins = [
|
|
27
|
+
"</absolute/path/to/plugin-1/directory>",
|
|
28
|
+
"</absolute/path/to/plugin-2/directory>"
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
# The `master` is a field that has to be composed of an
|
|
32
|
+
# `address` or `zookeeper` field, but not both. For example:
|
|
33
|
+
[master]
|
|
34
|
+
address = "10.10.0.30:5050"
|
|
35
|
+
principal = "username"
|
|
36
|
+
secret = "password"
|
|
37
|
+
|
|
38
|
+
[agent]
|
|
39
|
+
ssl = true
|
|
40
|
+
ssl_verify = false
|
|
41
|
+
principal = "username"
|
|
42
|
+
secret = "password"
|
|
43
|
+
timeout = 5
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
You can override the location of this configuration file using
|
|
47
|
+
the environment variable `MESOS_CLI_CONFIG`.
|
|
48
|
+
|
|
49
|
+
## How to use it
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
$ mesos-cli
|
|
53
|
+
|
|
54
|
+
Mesos CLI
|
|
55
|
+
|
|
56
|
+
Usage:
|
|
57
|
+
mesos (-h | --help)
|
|
58
|
+
mesos --version
|
|
59
|
+
mesos <command> [<args>...]
|
|
60
|
+
|
|
61
|
+
Options:
|
|
62
|
+
-h --help Show this screen.
|
|
63
|
+
--version Show version info.
|
|
64
|
+
|
|
65
|
+
Commands:
|
|
66
|
+
agent Interacts with the Mesos agents
|
|
67
|
+
config Interacts with the Mesos CLI configuration file
|
|
68
|
+
framework Interacts with the Mesos Frameworks
|
|
69
|
+
task Interacts with the tasks running in a Mesos cluster
|
|
70
|
+
|
|
71
|
+
See 'mesos help <command>' for more information on a specific command.
|
|
72
|
+
|
|
73
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
|
3
|
+
# distributed with this work for additional information
|
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
|
6
|
+
# "License"); you may not use this file except in compliance
|
|
7
|
+
# with the License. You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
Client library for the Mesos HTTP ReST API
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
__version__ = '0.0.0.dev'
|
|
22
|
+
|
|
23
|
+
__all__ = ['exceptions', 'http', 'recordio']
|
|
24
|
+
from . import exceptions
|
|
25
|
+
from . import http
|
|
26
|
+
from . import recordio
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
|
3
|
+
# distributed with this work for additional information
|
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
|
6
|
+
# "License"); you may not use this file except in compliance
|
|
7
|
+
# with the License. You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
Mesos CLI Module
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
# pylint: disable=cyclic-import
|
|
22
|
+
from . import config
|
|
23
|
+
from . import plugins
|
|
24
|
+
|
|
25
|
+
from . import exceptions
|
|
26
|
+
from . import util
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
|
3
|
+
# distributed with this work for additional information
|
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
|
6
|
+
# "License"); you may not use this file except in compliance
|
|
7
|
+
# with the License. You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
Config class to manage the configuration file.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import os
|
|
22
|
+
import toml
|
|
23
|
+
|
|
24
|
+
import requests
|
|
25
|
+
|
|
26
|
+
from avmesos import cli
|
|
27
|
+
from avmesos.cli.constants import DEFAULT_MASTER_IP
|
|
28
|
+
from avmesos.cli.constants import DEFAULT_MASTER_PORT
|
|
29
|
+
from avmesos.cli.exceptions import CLIException
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Config():
|
|
33
|
+
"""
|
|
34
|
+
The Config class loads the configuration file on initialization and has
|
|
35
|
+
one method for each element that can be specified in the config file.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(self, settings):
|
|
39
|
+
# Load the configuration file path for the CLI.
|
|
40
|
+
if os.environ.get("MESOS_CLI_CONFIG"):
|
|
41
|
+
self.path = os.environ["MESOS_CLI_CONFIG"]
|
|
42
|
+
else:
|
|
43
|
+
self.path = settings.DEFAULT_MESOS_CLI_CONFIG
|
|
44
|
+
|
|
45
|
+
# Load the configuration file as a TOML file.
|
|
46
|
+
try:
|
|
47
|
+
self.data = toml.load(self.path)
|
|
48
|
+
except Exception as exception:
|
|
49
|
+
raise CLIException("Error loading config file as TOML: {error}"
|
|
50
|
+
.format(error=exception))
|
|
51
|
+
|
|
52
|
+
def master(self):
|
|
53
|
+
"""
|
|
54
|
+
Parse the master info in the configuration file and return
|
|
55
|
+
its IP address and the port where Mesos is running.
|
|
56
|
+
"""
|
|
57
|
+
master = "{ip}:{port}".format(ip=DEFAULT_MASTER_IP,
|
|
58
|
+
port=DEFAULT_MASTER_PORT)
|
|
59
|
+
|
|
60
|
+
if "master" in self.data:
|
|
61
|
+
if not isinstance(self.data["master"], dict):
|
|
62
|
+
raise CLIException("The 'master' field must be a dictionary")
|
|
63
|
+
|
|
64
|
+
if ("address" not in self.data["master"] and
|
|
65
|
+
"zookeeper" not in self.data["master"]):
|
|
66
|
+
raise CLIException("The 'master' field must either"
|
|
67
|
+
" contain an 'address' field or"
|
|
68
|
+
" a 'zookeeper' dictionary")
|
|
69
|
+
if ("address" in self.data["master"] and
|
|
70
|
+
"zookeeper" in self.data["master"]):
|
|
71
|
+
raise CLIException("The 'master' field should only contain "
|
|
72
|
+
" an 'address' field or a 'zookeeper'"
|
|
73
|
+
" dictionary but not both")
|
|
74
|
+
|
|
75
|
+
if "address" in self.data["master"]:
|
|
76
|
+
master_address = self.data["master"]["address"]
|
|
77
|
+
try:
|
|
78
|
+
master = cli.util.sanitize_address(master_address)
|
|
79
|
+
except Exception as exception:
|
|
80
|
+
raise CLIException("The 'master' address {address} is"
|
|
81
|
+
" formatted incorrectly: {error}"
|
|
82
|
+
.format(address=master_address,
|
|
83
|
+
error=exception))
|
|
84
|
+
|
|
85
|
+
if "zookeeper" in self.data["master"]:
|
|
86
|
+
zk_field = self.data["master"]["zookeeper"]
|
|
87
|
+
|
|
88
|
+
if ("addresses" not in zk_field or
|
|
89
|
+
not isinstance(zk_field["addresses"], list)):
|
|
90
|
+
raise CLIException("The 'zookeeper' field must contain"
|
|
91
|
+
" an 'addresses' list")
|
|
92
|
+
|
|
93
|
+
if ("path" not in zk_field or
|
|
94
|
+
not isinstance(zk_field["path"], str)):
|
|
95
|
+
raise CLIException("The 'zookeeper' field must contain"
|
|
96
|
+
" a 'path' field")
|
|
97
|
+
|
|
98
|
+
if not zk_field["path"].startswith("/"):
|
|
99
|
+
raise CLIException("The 'zookeeper' field 'path'"
|
|
100
|
+
" must start with a '/'")
|
|
101
|
+
if len(zk_field["path"]) == 1:
|
|
102
|
+
raise CLIException("The 'zookeeper' field 'path' should"
|
|
103
|
+
" be nested ('/' is not supported)")
|
|
104
|
+
|
|
105
|
+
for address in zk_field["addresses"]:
|
|
106
|
+
try:
|
|
107
|
+
cli.util.sanitize_address(address)
|
|
108
|
+
except Exception as exception:
|
|
109
|
+
raise CLIException("The 'zookeeper' address {address}"
|
|
110
|
+
" is formatted incorrectly: {error}"
|
|
111
|
+
.format(address=address,
|
|
112
|
+
error=exception))
|
|
113
|
+
try:
|
|
114
|
+
master = cli.util.zookeeper_resolve_leader(
|
|
115
|
+
zk_field["addresses"], zk_field["path"])
|
|
116
|
+
except Exception as exception:
|
|
117
|
+
raise CLIException("Could not resolve the"
|
|
118
|
+
" leading master: {error}"
|
|
119
|
+
.format(error=exception))
|
|
120
|
+
|
|
121
|
+
return master
|
|
122
|
+
|
|
123
|
+
def principal(self):
|
|
124
|
+
"""
|
|
125
|
+
Return the principal in the configuration file
|
|
126
|
+
"""
|
|
127
|
+
return self.data["master"].get("principal")
|
|
128
|
+
|
|
129
|
+
def secret(self):
|
|
130
|
+
"""
|
|
131
|
+
Return the secret in the configuration file
|
|
132
|
+
"""
|
|
133
|
+
return self.data["master"].get("secret")
|
|
134
|
+
|
|
135
|
+
def agent_ssl(self, default=False):
|
|
136
|
+
"""
|
|
137
|
+
Return if the agent support ssl
|
|
138
|
+
"""
|
|
139
|
+
if "agent" in self.data:
|
|
140
|
+
agent_ssl = self.data["agent"].get("ssl", default)
|
|
141
|
+
if not isinstance(agent_ssl, bool):
|
|
142
|
+
raise CLIException("The 'agent->ssl' field"
|
|
143
|
+
" must be True/False")
|
|
144
|
+
|
|
145
|
+
return agent_ssl
|
|
146
|
+
|
|
147
|
+
return default
|
|
148
|
+
|
|
149
|
+
def agent_ssl_verify(self, default=False):
|
|
150
|
+
"""
|
|
151
|
+
Return if the ssl certificate should be verified
|
|
152
|
+
"""
|
|
153
|
+
if "agent" in self.data:
|
|
154
|
+
ssl_verify = self.data["agent"].get("ssl_verify", default)
|
|
155
|
+
if not isinstance(ssl_verify, bool):
|
|
156
|
+
raise CLIException("The 'agent->ssl_verify' field"
|
|
157
|
+
" must be True/False")
|
|
158
|
+
|
|
159
|
+
return ssl_verify
|
|
160
|
+
|
|
161
|
+
return default
|
|
162
|
+
|
|
163
|
+
def ssl_verify(self, default=False):
|
|
164
|
+
"""
|
|
165
|
+
Return if the ssl certificate should be verified
|
|
166
|
+
"""
|
|
167
|
+
if "master" in self.data:
|
|
168
|
+
ssl_verify = self.data["master"].get("ssl_verify", default)
|
|
169
|
+
if not isinstance(ssl_verify, bool):
|
|
170
|
+
raise CLIException("The 'master->ssl_verify' field"
|
|
171
|
+
" must be True/False")
|
|
172
|
+
|
|
173
|
+
return ssl_verify
|
|
174
|
+
|
|
175
|
+
return default
|
|
176
|
+
|
|
177
|
+
def agent_timeout(self, default=5):
|
|
178
|
+
"""
|
|
179
|
+
Return the connection timeout of the agent
|
|
180
|
+
"""
|
|
181
|
+
if "agent" in self.data:
|
|
182
|
+
timeout = self.data["agent"].get("timeout", default)
|
|
183
|
+
if not isinstance(timeout, int):
|
|
184
|
+
raise CLIException("The 'agent->timeout' field"
|
|
185
|
+
" must be a number in seconds")
|
|
186
|
+
|
|
187
|
+
return timeout
|
|
188
|
+
|
|
189
|
+
return default
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def agent_principal(self):
|
|
193
|
+
"""
|
|
194
|
+
Return the principal in the configuration file
|
|
195
|
+
"""
|
|
196
|
+
if "agent" in self.data:
|
|
197
|
+
return self.data["agent"].get("principal")
|
|
198
|
+
|
|
199
|
+
return None
|
|
200
|
+
|
|
201
|
+
def agent_secret(self):
|
|
202
|
+
"""
|
|
203
|
+
Return the secret in the configuration file
|
|
204
|
+
"""
|
|
205
|
+
if "agent" in self.data:
|
|
206
|
+
return self.data["agent"].get("secret")
|
|
207
|
+
|
|
208
|
+
return None
|
|
209
|
+
|
|
210
|
+
def plugins(self):
|
|
211
|
+
"""
|
|
212
|
+
Parse the plugins listed in the configuration file and return them.
|
|
213
|
+
"""
|
|
214
|
+
# Allow extra plugins to be pulled in from the configuration file.
|
|
215
|
+
if "plugins" in self.data:
|
|
216
|
+
if not isinstance(self.data["plugins"], list):
|
|
217
|
+
raise CLIException("Unable to parse config file '{path}':"
|
|
218
|
+
" 'plugins' field must be a list"
|
|
219
|
+
.format(path=self.path))
|
|
220
|
+
|
|
221
|
+
for plugin in self.data["plugins"]:
|
|
222
|
+
if not os.path.exists(plugin):
|
|
223
|
+
raise CLIException("Plugin path not found: {path}"
|
|
224
|
+
.format(path=plugin))
|
|
225
|
+
return self.data["plugins"]
|
|
226
|
+
|
|
227
|
+
return []
|
|
228
|
+
|
|
229
|
+
def authentication_header(self):
|
|
230
|
+
"""
|
|
231
|
+
Return the BasicAuth authentication header
|
|
232
|
+
"""
|
|
233
|
+
if (self.agent_principal() is not None
|
|
234
|
+
and self.agent_secret() is not None):
|
|
235
|
+
return requests.auth.HTTPBasicAuth(
|
|
236
|
+
self.agent_principal(),
|
|
237
|
+
self.agent_secret()
|
|
238
|
+
)
|
|
239
|
+
return None
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
|
3
|
+
# distributed with this work for additional information
|
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
|
6
|
+
# "License"); you may not use this file except in compliance
|
|
7
|
+
# with the License. You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
A collection of constants useful for the CLI.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
DEFAULT_MASTER_IP = "127.0.0.1"
|
|
22
|
+
DEFAULT_MASTER_PORT = "5050"
|
|
23
|
+
|
|
24
|
+
DEFAULT_AGENT_IP = "127.0.0.1"
|
|
25
|
+
DEFAULT_AGENT_PORT = "5051"
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
|
3
|
+
# distributed with this work for additional information
|
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
|
6
|
+
# "License"); you may not use this file except in compliance
|
|
7
|
+
# with the License. You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
Unfortunately, docopt doesn't support multi-word commands. This is
|
|
19
|
+
important for supporting things like:
|
|
20
|
+
|
|
21
|
+
mesos cluster ps <args>...
|
|
22
|
+
|
|
23
|
+
However, it looks like some plans are in place for supporting it in the
|
|
24
|
+
future: https://github.com/docopt/docopt/issues/41
|
|
25
|
+
|
|
26
|
+
The proposal is to add a "program" keyword argument to docopt to specify the
|
|
27
|
+
full set of words used to represent the command. Since this is not yet
|
|
28
|
+
supported officially, we include the hack below to make it work for us. We
|
|
29
|
+
essentially intercept the call to docopt and make it work with such a "program"
|
|
30
|
+
argument.
|
|
31
|
+
|
|
32
|
+
To make it work, we inspect the value of "program" and search and replace all
|
|
33
|
+
instances of it in the usage string with a transformed version of it to make it
|
|
34
|
+
a single word (i.e. we replace all spaces with dashes: echo $program | s/
|
|
35
|
+
/-/g). This essentially turns all multi-word commands in the usage string into
|
|
36
|
+
dash-separated single words (e.g., s/mesos cluster ps/mesos-cluster-ps/g). With
|
|
37
|
+
this in place, we then pass this usage string to the original docopt for
|
|
38
|
+
parsing.
|
|
39
|
+
|
|
40
|
+
Unfortunately, doing things this way means that docopt (by default) will print
|
|
41
|
+
the usage string containing the dashes. To avoid this, we intercept all paths
|
|
42
|
+
where docopt does the printing itself, and transform the usage string back to
|
|
43
|
+
its original form.
|
|
44
|
+
|
|
45
|
+
Hopefully we can remove this brutal hack at some point in the future
|
|
46
|
+
once docopt supports the "program" argument natively.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
import os
|
|
50
|
+
import sys
|
|
51
|
+
|
|
52
|
+
# pylint: disable=import-error
|
|
53
|
+
from docopt import docopt as real_docopt, DocoptExit
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def docopt(usage, **keywords):
|
|
57
|
+
""" A wrapper around the real docopt parser. """
|
|
58
|
+
new_usage = usage
|
|
59
|
+
|
|
60
|
+
if "program" in keywords:
|
|
61
|
+
program = keywords.pop("program")
|
|
62
|
+
new_usage = usage.replace(program, program.replace(" ", "-"))
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
stdout = sys.stdout
|
|
66
|
+
|
|
67
|
+
with open(os.devnull, 'w') as nullfile:
|
|
68
|
+
sys.stdout = nullfile
|
|
69
|
+
arguments = real_docopt(new_usage, **keywords)
|
|
70
|
+
sys.stdout = stdout
|
|
71
|
+
|
|
72
|
+
return arguments
|
|
73
|
+
|
|
74
|
+
except DocoptExit:
|
|
75
|
+
sys.stdout = stdout
|
|
76
|
+
print(usage.strip(), file=sys.stderr)
|
|
77
|
+
sys.exit(1)
|
|
78
|
+
|
|
79
|
+
except SystemExit:
|
|
80
|
+
sys.stdout = stdout
|
|
81
|
+
|
|
82
|
+
if "argv" in keywords and any(h in ("-h", "--help")
|
|
83
|
+
for h in keywords["argv"]):
|
|
84
|
+
print(usage.strip())
|
|
85
|
+
elif "version" in keywords and any(v in ("--version")
|
|
86
|
+
for v in keywords["argv"]):
|
|
87
|
+
print(keywords["version"].strip())
|
|
88
|
+
|
|
89
|
+
sys.exit()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
|
3
|
+
# distributed with this work for additional information
|
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
|
6
|
+
# "License"); you may not use this file except in compliance
|
|
7
|
+
# with the License. You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
CLIException Class
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
class CLIException(Exception):
|
|
22
|
+
"""
|
|
23
|
+
Exceptions class to handle all CLI errors.
|
|
24
|
+
"""
|