mirror of
https://github.com/Hopiu/portainer-cli.git
synced 2026-03-16 22:10:34 +00:00
Compare commits
9 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
083e0e95f0 | ||
|
|
bec593bf40 | ||
|
|
54c4cede32 | ||
|
|
42cca1ad8d | ||
|
|
d526a783ec | ||
|
|
bb34e5ef5c | ||
|
|
1adea2c6d6 | ||
|
|
7101e255be | ||
|
|
ddcc8e7887 |
3 changed files with 436 additions and 29 deletions
119
README.md
119
README.md
|
|
@ -47,24 +47,47 @@ portainer-cli login username password
|
|||
portainer-cli login douglas d1234
|
||||
```
|
||||
|
||||
### update_stack command
|
||||
### create_stack command
|
||||
|
||||
Update stack.
|
||||
Create a stack.
|
||||
|
||||
```bash
|
||||
portainer-cli update_stack id endpoint_id [stack_file]
|
||||
portainer-cli create_stack -n stack_name -e endpoint_id -sf stack_file
|
||||
```
|
||||
|
||||
**E.g:**
|
||||
|
||||
```bash
|
||||
portainer-cli update_stack 2 1 docker-compose.yml
|
||||
portainer-cli create_stack -n stack_name -e 1 stack-test -sf docker-compose.yml
|
||||
```
|
||||
|
||||
#### Flags
|
||||
|
||||
| Flag | Description |
|
||||
|--|--|
|
||||
| `-n` or `-stack-name` | Stack name |
|
||||
| `-e` or `-endpoint-id` | Endpoint id (required) |
|
||||
| `-sf` or `-stack-file` |Stack file |
|
||||
| `-ef` or `-env-file` | Pass env file path, usually `.env` |
|
||||
|
||||
### update_stack command
|
||||
|
||||
Update a stack.
|
||||
|
||||
```bash
|
||||
portainer-cli update_stack -s stack_id -e endpoint_id -sf stack_file
|
||||
```
|
||||
|
||||
**E.g:**
|
||||
|
||||
```bash
|
||||
portainer-cli update_stack -s 18 -e 1 -sf docker-compose.yml
|
||||
```
|
||||
|
||||
#### Environment variables arguments
|
||||
|
||||
```bash
|
||||
portainer-cli update_stack id endpoint_id [stack_file] --env.var=value
|
||||
portainer-cli update_stack id -s stack_id -e endpoint_id -sf stack_file --env.var=value
|
||||
```
|
||||
|
||||
Where `var` is the environment variable name and `value` is the environment variable value.
|
||||
|
|
@ -73,9 +96,95 @@ Where `var` is the environment variable name and `value` is the environment vari
|
|||
|
||||
| Flag | Description |
|
||||
|--|--|
|
||||
| `-s` or `-stack-id` | Stack id |
|
||||
| `-e` or `-endpoint-id` | Endpoint id (required) |
|
||||
| `-sf` or `-stack-file` |Stack file |
|
||||
| `-ef` or `-env-file` | Pass env file path, usually `.env` |
|
||||
| `-p` or `--prune` | Prune services |
|
||||
| `-c` or `--clear-env` | Clear all environment variables |
|
||||
|
||||
### create_or_update_stack command
|
||||
|
||||
Create or update a stack based on it's name.
|
||||
|
||||
```bash
|
||||
portainer-cli create_or_update_stack -n stack_name -e endpoint_id -sf stack_file
|
||||
```
|
||||
|
||||
**E.g:**
|
||||
|
||||
```bash
|
||||
portainer-cli update_stack -s 18 -e 1 -sf docker-compose.yml
|
||||
```
|
||||
|
||||
#### Environment variables arguments
|
||||
|
||||
```bash
|
||||
portainer-cli create_or_update_stack -n stack_name -e endpoint_id -sf stack_file --env.var=value
|
||||
```
|
||||
|
||||
Where `var` is the environment variable name and `value` is the environment variable value.
|
||||
|
||||
#### Flags
|
||||
|
||||
| Flag | Description |
|
||||
|--|--|
|
||||
| `-n` or `-stack-name` | Stack name |
|
||||
| `-e` or `-endpoint-id` | Endpoint id (required) |
|
||||
| `-sf` or `-stack-file` |Stack file |
|
||||
| `-ef` or `-env-file` | Pass env file path, usually `.env` |
|
||||
| `-p` or `--prune` | Prune services |
|
||||
| `-c` or `--clear-env` | Clear all environment variables |
|
||||
|
||||
### update_stack_acl command
|
||||
|
||||
Update acl associated to a stack
|
||||
|
||||
```bash
|
||||
portainer-cli update_stack_acl -s stack_id -e endpoint_id -o ownership_type
|
||||
```
|
||||
|
||||
Remark : you can either update by stack_id or stack_name (`-s` or `-n`)
|
||||
|
||||
**E.g:**
|
||||
|
||||
```bash
|
||||
portainer-cli update_stack_acl -n stack-test -e 1 -o restricted -u user1,user2 -t team1,team2
|
||||
```
|
||||
|
||||
#### Flags
|
||||
|
||||
| Flag | Description |
|
||||
|--|--|
|
||||
| `-s` or `-stack-id` | Stack id |
|
||||
| `-n` or `-stack-name` | Stack name |
|
||||
| `-e` or `-endpoint-id` | Endpoint id (required) |
|
||||
| `-o` or `-ownership-type` | Ownership type (`admin`|`restricted`,`public`) (required) |
|
||||
| `-u` or `-users` | Comma separated list of user names (when `restricted`) |
|
||||
| `-t` or `-teams` | Comma separated list of team names (when `restricted`) |
|
||||
| `-c` or `-clear` | Clear users and teams before updateing them (when `restricted`) |
|
||||
|
||||
### get_stack_id command
|
||||
|
||||
Get stack id by it's name. return -1 if the stack does not exist
|
||||
|
||||
```bash
|
||||
portainer-cli get_stack_id -n stack_name -e endpoint_id
|
||||
```
|
||||
|
||||
**E.g:**
|
||||
|
||||
```bash
|
||||
portainer-cli get_stack_id -n stack-test -e 1
|
||||
```
|
||||
|
||||
#### Flags
|
||||
|
||||
| Flag | Description |
|
||||
|--|--|
|
||||
| `-n` or `-stack-name` | Stack name |
|
||||
| `-e` or `-endpoint-id` | Endpoint id (required) |
|
||||
|
||||
### update_registry command
|
||||
|
||||
Update registry.
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ try:
|
|||
except NameError:
|
||||
FileNotFoundError = IOError
|
||||
|
||||
__version__ = '0.2.2'
|
||||
__version__ = '0.3.0'
|
||||
|
||||
logger = logging.getLogger('portainer-cli')
|
||||
|
||||
|
|
@ -22,33 +22,41 @@ env_arg_regex = r'--env\.(.+)=(.+)'
|
|||
|
||||
def env_arg_to_dict(s):
|
||||
split = re.split(env_arg_regex, s)
|
||||
return {
|
||||
'name': split[1],
|
||||
'value': split[2],
|
||||
}
|
||||
return (split[1], split[2],)
|
||||
|
||||
|
||||
class PortainerCLI(object):
|
||||
COMMAND_CONFIGURE = 'configure'
|
||||
COMMAND_LOGIN = 'login'
|
||||
COMMAND_REQUEST = 'request'
|
||||
COMMAND_CREATE_STACK = 'create_stack'
|
||||
COMMAND_UPDATE_STACK = 'update_stack'
|
||||
COMMAND_UPDATE_STACK_ACL = 'update_stack_acl'
|
||||
COMMAND_CREATE_OR_UPDATE_STACK = 'create_or_update_stack'
|
||||
COMMAND_GET_STACK_ID = 'get_stack_id'
|
||||
COMMAND_UPDATE_REGISTRY = 'update_registry'
|
||||
COMMANDS = [
|
||||
COMMAND_CONFIGURE,
|
||||
COMMAND_LOGIN,
|
||||
COMMAND_REQUEST,
|
||||
COMMAND_CREATE_STACK,
|
||||
COMMAND_UPDATE_STACK,
|
||||
COMMAND_UPDATE_REGISTRY,
|
||||
COMMAND_UPDATE_STACK_ACL,
|
||||
COMMAND_CREATE_OR_UPDATE_STACK,
|
||||
COMMAND_GET_STACK_ID,
|
||||
COMMAND_UPDATE_REGISTRY
|
||||
]
|
||||
|
||||
METHOD_GET = 'GET'
|
||||
METHOD_POST = 'POST'
|
||||
METHOD_PUT = 'PUT'
|
||||
METHOD_DELETE = 'DELETE'
|
||||
|
||||
local = False
|
||||
_base_url = 'http://localhost:9000/'
|
||||
_jwt = None
|
||||
_proxies = {}
|
||||
_swarm_id = None
|
||||
|
||||
@property
|
||||
def base_url(self):
|
||||
|
|
@ -70,6 +78,32 @@ class PortainerCLI(object):
|
|||
self._jwt = value
|
||||
self.persist()
|
||||
|
||||
@property
|
||||
def proxies(self):
|
||||
return self._proxies
|
||||
|
||||
@proxies.setter
|
||||
def proxies(self, value):
|
||||
try:
|
||||
self._proxies['http'] = os.environ['HTTP_PROXY']
|
||||
except KeyError:
|
||||
self._proxies['http'] = ''
|
||||
try:
|
||||
self._proxies['https'] = os.environ['HTTPS_PROXY']
|
||||
except KeyError:
|
||||
self._proxies['https'] = ''
|
||||
if self._proxies['http'] == '' and self._proxies['https'] == '':
|
||||
self._proxies = {}
|
||||
|
||||
@property
|
||||
def swarm_id(self):
|
||||
return self._swarm_id
|
||||
|
||||
@swarm_id.setter
|
||||
def swarm_id(self, value):
|
||||
self._swarm_id = value
|
||||
self.persist()
|
||||
|
||||
@property
|
||||
def data_path(self):
|
||||
if self.local:
|
||||
|
|
@ -118,40 +152,295 @@ class PortainerCLI(object):
|
|||
logger.info('logged with jwt: {}'.format(jwt))
|
||||
self.jwt = jwt
|
||||
|
||||
def get_users(self):
|
||||
users_url = 'users'
|
||||
return self.request(users_url, self.METHOD_GET).json()
|
||||
|
||||
# retrieve users by their names
|
||||
def get_users_by_name(self, names):
|
||||
all_users = self.get_users()
|
||||
if not all_users:
|
||||
logger.debug('No users found')
|
||||
return []
|
||||
users=[]
|
||||
for name in names:
|
||||
# searching for user
|
||||
user = next(u for u in all_users if u['Username'] == name)
|
||||
if not user:
|
||||
logger.warn('User with name \'{}\' not found'.format(name))
|
||||
else:
|
||||
logger.debug('User with name \'{}\' found'.format(name))
|
||||
users.append(user)
|
||||
return users
|
||||
|
||||
# retrieve users by their names
|
||||
def get_users_by_name(self, names):
|
||||
all_users = self.get_users()
|
||||
all_users_by_name = dict(map(
|
||||
lambda u: (u['Username'], u),
|
||||
all_users,
|
||||
))
|
||||
users = []
|
||||
for name in names:
|
||||
user = all_users_by_name.get(name)
|
||||
if not user:
|
||||
logger.warn('User with name \'{}\' not found'.format(name))
|
||||
else:
|
||||
logger.debug('User with name \'{}\' found'.format(name))
|
||||
users.append(user)
|
||||
return users
|
||||
|
||||
def get_teams(self):
|
||||
teams_url = 'teams'
|
||||
return self.request(teams_url, self.METHOD_GET).json()
|
||||
|
||||
# retrieve teams by their names
|
||||
def get_teams_by_name(self, names):
|
||||
all_teams = self.get_teams()
|
||||
all_teams_by_name = dict(map(
|
||||
lambda u: (u['Name'], u),
|
||||
all_teams,
|
||||
))
|
||||
teams = []
|
||||
for name in names:
|
||||
team = all_teams_by_name.get(name)
|
||||
if not team:
|
||||
logger.warn('Team with name \'{}\' not found'.format(name))
|
||||
else:
|
||||
logger.debug('Team with name \'{}\' found'.format(name))
|
||||
teams.append(team)
|
||||
return teams
|
||||
|
||||
def get_stacks(self):
|
||||
stack_url = 'stacks'
|
||||
return self.request(stack_url, self.METHOD_GET).json()
|
||||
|
||||
def get_stack_by_id(self, stack_id, endpoint_id):
|
||||
stack_url = 'stacks/{}?endpointId={}'.format(
|
||||
stack_id,
|
||||
endpoint_id,
|
||||
)
|
||||
stack = self.request(stack_url).json()
|
||||
if not stack:
|
||||
raise Exception('Stack with id={} does not exist'.format(stack_id))
|
||||
return stack
|
||||
|
||||
def get_stack_by_name(self, stack_name, endpoint_id, mandatory=False):
|
||||
result = self.get_stacks()
|
||||
if result:
|
||||
for stack in result:
|
||||
if stack['Name'] == stack_name and stack['EndpointId'] == endpoint_id:
|
||||
return stack
|
||||
if mandatory:
|
||||
raise Exception('Stack with name={} and endpoint_id={} does not exist'.format(stack_name, endpoint_id))
|
||||
else:
|
||||
return None
|
||||
|
||||
# Retrieve the stack if. -1 if the stack does not exist
|
||||
@plac.annotations(
|
||||
stack_name=('Stack name', 'option', 'n'),
|
||||
endpoint_id=('Endpoint id', 'option', 'e', int)
|
||||
)
|
||||
def get_stack_id(self, stack_name, endpoint_id):
|
||||
stack = self.get_stack_by_name(stack_name, endpoint_id)
|
||||
if not stack:
|
||||
logger.debug('Stack with name={} does not exist'.format(stack_name))
|
||||
return -1
|
||||
logger.debug('Stack with name={} -> id={}'.format(stack_name, stack['Id']))
|
||||
return stack['Id']
|
||||
|
||||
def extract_env(self, env_file='', *args):
|
||||
# Handle --env.PARAM=VALUE
|
||||
env_args = filter(
|
||||
lambda x: re.match(env_arg_regex, x),
|
||||
args,
|
||||
)
|
||||
env = dict(map(
|
||||
lambda x: env_arg_to_dict(x),
|
||||
env_args,
|
||||
))
|
||||
# Hand environement file
|
||||
if env_file:
|
||||
for env_line in open(env_file).readlines():
|
||||
env_line = env_line.strip()
|
||||
if not env_line or env_line.startswith('#') or '=' not in env_line:
|
||||
continue
|
||||
k, v = env_line.split('=', 1)
|
||||
k, v = k.strip(), v.strip()
|
||||
env[k] = v
|
||||
|
||||
return env
|
||||
|
||||
@plac.annotations(
|
||||
stack_name=('Stack name', 'option', 'n', str),
|
||||
endpoint_id=('Endpoint id', 'option', 'e', int),
|
||||
stack_file=('Stack file', 'option', 'sf'),
|
||||
env_file=('Environment Variable file', 'option', 'ef'),
|
||||
prune=('Prune services', 'flag', 'p'),
|
||||
clear_env=('Clear all env vars', 'flag', 'c'),
|
||||
)
|
||||
def create_or_update_stack(self, stack_name, endpoint_id, stack_file='', env_file='', prune=False, clear_env=False, *args):
|
||||
logger.debug('create_or_update_stack')
|
||||
stack_id = self.get_stack_id(stack_name, endpoint_id)
|
||||
if stack_id == -1:
|
||||
self.create_stack(stack_name, endpoint_id, stack_file, env_file, *args)
|
||||
else:
|
||||
self.update_stack(stack_id, endpoint_id, stack_file, env_file, prune, clear_env, *args)
|
||||
|
||||
@plac.annotations(
|
||||
stack_name=('Stack name', 'option', 'n'),
|
||||
endpoint_id=('Endpoint id', 'option', 'e', int),
|
||||
stack_file=('Environment Variable file', 'option', 'sf'),
|
||||
env_file=('Environment Variable file', 'option', 'ef')
|
||||
)
|
||||
def create_stack(self, stack_name, endpoint_id, stack_file='', env_file='', *args):
|
||||
logger.info('Creating stack name={}'.format(stack_name))
|
||||
stack_url = 'stacks?type=1&method=string&endpointId={}'.format(
|
||||
endpoint_id
|
||||
)
|
||||
swarm_url = 'endpoints/{}/docker/swarm'.format(endpoint_id)
|
||||
swarm_id = self.request(swarm_url, self.METHOD_GET).json().get('ID')
|
||||
self.swarm_id = swarm_id
|
||||
stack_file_content = open(stack_file).read()
|
||||
|
||||
env = self.extract_env(env_file, *args)
|
||||
final_env = list(
|
||||
map(
|
||||
lambda x: {'name': x[0], 'value': x[1]},
|
||||
env.items()
|
||||
),
|
||||
)
|
||||
data = {
|
||||
'StackFileContent': stack_file_content,
|
||||
'SwarmID': self.swarm_id,
|
||||
'Name': stack_name,
|
||||
'Env': final_env if len(final_env) > 0 else []
|
||||
}
|
||||
logger.debug('create stack data: {}'.format(data))
|
||||
self.request(
|
||||
stack_url,
|
||||
self.METHOD_POST,
|
||||
data,
|
||||
)
|
||||
|
||||
def create_or_update_resource_control(self, stack, public, users, teams):
|
||||
resource_control = stack['ResourceControl']
|
||||
if resource_control and resource_control['Id'] != 0:
|
||||
resource_path = 'resource_controls/{}'.format(resource_control['Id'])
|
||||
data = {
|
||||
'Public': public,
|
||||
'Users': users,
|
||||
'Teams': teams
|
||||
}
|
||||
logger.debug('Updating stack acl {} for stack {}: {}'.format(resource_control['Id'], stack['Id'], data))
|
||||
self.request(resource_path, self.METHOD_PUT, data)
|
||||
else:
|
||||
resource_path = 'resource_controls'
|
||||
data = {
|
||||
'Type': 'stack',
|
||||
'ResourceID': stack['Name'],
|
||||
'Public': public,
|
||||
'Users': users,
|
||||
'Teams': teams
|
||||
}
|
||||
logger.debug('Creating stack acl for stack {}: {}'.format(stack['Id'], data))
|
||||
self.request(resource_path, self.METHOD_POST, data)
|
||||
|
||||
|
||||
@plac.annotations(
|
||||
stack_id=('Stack id', 'option', 's', int),
|
||||
stack_name=('Stack name', 'option', 'n', str),
|
||||
endpoint_id=('Endpoint id', 'option', 'e', int),
|
||||
ownership_type=('Ownership type', 'option', 'o', str, ['admin', 'restricted', 'public']),
|
||||
users=('Allowed usernames (comma separated - restricted ownership_type only)', 'option', 'u'),
|
||||
teams=('Allowed teams (comma separated - restricted ownership_type only)', 'option', 't'),
|
||||
clear=('Clear acl (restricted ownership_type only)', 'flag', 'c')
|
||||
)
|
||||
def update_stack_acl(self, stack_id, stack_name, endpoint_id, ownership_type, users, teams, clear=False):
|
||||
stack = None
|
||||
if stack_id:
|
||||
stack = self.get_stack_by_id(stack_id, endpoint_id)
|
||||
elif stack_name:
|
||||
stack = self.get_stack_by_name(stack_name, endpoint_id, True)
|
||||
else:
|
||||
raise Exception('Please provide either stack_name or stack_id')
|
||||
|
||||
logger.info('Updating acl of stack name={} - type={}'.format(stack['Name'], ownership_type))
|
||||
|
||||
resource_control = stack['ResourceControl']
|
||||
|
||||
if ownership_type == 'admin':
|
||||
if resource_control and resource_control['Id'] != 0:
|
||||
logger.debug('Deleting resource control with id {}'.format(resource_control['Id']))
|
||||
resource_path = 'resource_controls/{}'.format(resource_control['Id'])
|
||||
logger.debug('resource_path : {}'.format(resource_path))
|
||||
self.request(resource_path, self.METHOD_DELETE)
|
||||
else:
|
||||
logger.debug('Nothing to do')
|
||||
elif ownership_type == 'public':
|
||||
self.create_or_update_resource_control(stack, True, [], [])
|
||||
elif ownership_type == 'restricted':
|
||||
users = map(lambda u: u['Id'], self.get_users_by_name(users.split(',')))
|
||||
teams = map(lambda t: t['Id'], self.get_teams_by_name(teams.split(',')))
|
||||
|
||||
if (not clear) and resource_control:
|
||||
logger.debug('Merging existing users / teams')
|
||||
users = list(set().union(users, map(lambda u: u['UserId'], resource_control['UserAccesses'])))
|
||||
teams = list(set().union(teams, map(lambda t: t['TeamId'], resource_control['TeamAccesses'])))
|
||||
|
||||
self.create_or_update_resource_control(stack, False, users, teams)
|
||||
|
||||
@plac.annotations(
|
||||
stack_id=('Stack id', 'option', 's', int),
|
||||
endpoint_id=('Endpoint id', 'option', 'e', int),
|
||||
stack_file=('Stack file', 'option', 'sf'),
|
||||
env_file=('Environment Variable file', 'option', 'ef'),
|
||||
prune=('Prune services', 'flag', 'p'),
|
||||
clear_env=('Clear all env vars', 'flag', 'c'),
|
||||
)
|
||||
def update_stack(self, id, endpoint_id, stack_file='', prune=False,
|
||||
clear_env=False, *args):
|
||||
def update_stack(self, stack_id, endpoint_id, stack_file='', env_file='',
|
||||
prune=False, clear_env=False, *args):
|
||||
logger.info('Updating stack id={}'.format(stack_id))
|
||||
stack_url = 'stacks/{}?endpointId={}'.format(
|
||||
id,
|
||||
stack_id,
|
||||
endpoint_id,
|
||||
)
|
||||
current = self.request(stack_url).json()
|
||||
current = self.get_stack_by_id(stack_id, endpoint_id)
|
||||
stack_file_content = ''
|
||||
if stack_file:
|
||||
stack_file_content = open(stack_file).read()
|
||||
else:
|
||||
stack_file_content = self.request(
|
||||
'stacks/{}/file?endpointId={}').format(
|
||||
id,
|
||||
'stacks/{}/file?endpointId={}'.format(
|
||||
stack_id,
|
||||
endpoint_id,
|
||||
).json().get('StackFileContent')
|
||||
env_args = filter(
|
||||
lambda x: re.match(env_arg_regex, x),
|
||||
args,
|
||||
)
|
||||
).json().get('StackFileContent')
|
||||
|
||||
env = self.extract_env(env_file, *args)
|
||||
|
||||
if not clear_env:
|
||||
current_env = dict(
|
||||
map(
|
||||
lambda x: (x.get('name'), x.get('value'),),
|
||||
current.get('Env'),
|
||||
),
|
||||
)
|
||||
current_env.update(env)
|
||||
env = current_env
|
||||
final_env = list(
|
||||
map(
|
||||
lambda x: {'name': x[0], 'value': x[1]},
|
||||
env.items()
|
||||
),
|
||||
)
|
||||
env = list(map(
|
||||
lambda x: env_arg_to_dict(x),
|
||||
env_args,
|
||||
))
|
||||
data = {
|
||||
'Id': id,
|
||||
'Id': stack_id,
|
||||
'StackFileContent': stack_file_content,
|
||||
'Prune': prune,
|
||||
'Env': env if len(env) > 0 or clear_env else current.get('Env'),
|
||||
'Env': final_env if len(final_env) > 0 else current.get('Env'),
|
||||
}
|
||||
logger.debug('update stack data: {}'.format(data))
|
||||
self.request(
|
||||
stack_url,
|
||||
self.METHOD_PUT,
|
||||
|
|
@ -204,7 +493,7 @@ class PortainerCLI(object):
|
|||
prepped.headers['Content-Length'] = len(prepped.body)
|
||||
if self.jwt:
|
||||
prepped.headers['Authorization'] = 'Bearer {}'.format(self.jwt)
|
||||
response = session.send(prepped)
|
||||
response = session.send(prepped, proxies=self.proxies, verify=False)
|
||||
logger.debug('request response: {}'.format(response.content))
|
||||
response.raise_for_status()
|
||||
if printc:
|
||||
|
|
@ -227,12 +516,21 @@ class PortainerCLI(object):
|
|||
logging.basicConfig(level=logging.DEBUG)
|
||||
self.local = local
|
||||
self.load()
|
||||
self.proxies = {}
|
||||
if command == self.COMMAND_CONFIGURE:
|
||||
plac.call(self.configure, args)
|
||||
elif command == self.COMMAND_LOGIN:
|
||||
plac.call(self.login, args)
|
||||
elif command == self.COMMAND_CREATE_STACK:
|
||||
plac.call(self.create_stack, args)
|
||||
elif command == self.COMMAND_UPDATE_STACK:
|
||||
plac.call(self.update_stack, args)
|
||||
elif command == self.COMMAND_UPDATE_STACK_ACL:
|
||||
plac.call(self.update_stack_acl, args)
|
||||
elif command == self.COMMAND_CREATE_OR_UPDATE_STACK:
|
||||
plac.call(self.create_or_update_stack, args)
|
||||
elif command == self.COMMAND_GET_STACK_ID:
|
||||
plac.call(self.get_stack_id, args)
|
||||
elif command == self.COMMAND_UPDATE_REGISTRY:
|
||||
plac.call(self.update_registry, args)
|
||||
elif command == self.COMMAND_REQUEST:
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -1,6 +1,6 @@
|
|||
import setuptools
|
||||
from portainer_cli import __version__
|
||||
|
||||
__version__ = '0.3.0'
|
||||
with open('README.md', 'r') as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue