Skip to content

Commit ff1a6e0

Browse files
authored
Release 1.5.2
2 parents 3da334f + 33ed0ab commit ff1a6e0

22 files changed

+1233
-290
lines changed

.travis.yml

+9-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ python:
1010

1111
install:
1212
- cd cli
13+
- if [[ $TRAVIS_PYTHON_VERSION == 3.3 ]]; then
14+
pip install 'setuptools==39.2.0' --force-reinstall;
15+
pip install -U enum34;
16+
fi
1317
- if [[ $TRAVIS_PYTHON_VERSION == 2.6 ]];
1418
then pip install -r requirements26.txt;
1519
else pip install -r requirements.txt;
@@ -19,4 +23,8 @@ install:
1923

2024
sudo: false
2125

22-
script: sh tests/test.sh
26+
script:
27+
- if [[ $TRAVIS_PYTHON_VERSION != 2.6 ]];
28+
then python cli/tests/cfncluster-unittest.py;
29+
fi
30+
- sh tests/test.sh

CHANGELOG.rst

+9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
CHANGELOG
33
=========
44

5+
1.5.2
6+
=====
7+
* feature:``cfncluster``: Added ClusterUser as a stack output. This makes it easier to get the username of the head node.
8+
* feature:``cfncluster``: Added `cfncluster ssh cluster_name`, this allows you to easily ssh into your clusters. It allows arbitrary command execution and extra ssh flags to be provided after the command. See https://cfncluster.readthedocs.io/en/latest/commands.html#ssh
9+
* change:``cfncluster``: Moved global cli flags to the command specific flags. For example `cfncluster --region us-east-1 create` now becomes `cfncluster create --region us-east-1`
10+
* bugfix:``cfncluster-cookbook``: Fix bug that prevented c5d/m5d instances from working
11+
* bugfix:``cfncluster-cookbook``: Set CPU as a consumable resource in slurm
12+
* bugfix:``cfncluster-node``: Fixed Slurm behavior to add CPU slots so multiple jobs can be scheduled on a single node
13+
514
1.5.1
615
=====
716
* change:``cfncluster``: Added "ec2:DescribeVolumes" permissions to

CONTRIBUTORS.txt

-17
This file was deleted.

amis.txt

+80-80
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,85 @@
11
# alinux
2-
ap-northeast-1: ami-0dde39e2d5b865e22
3-
ap-northeast-2: ami-00ff07cc9e3be7301
4-
ap-northeast-3: ami-00683abdf6e60ebcd
5-
ap-south-1: ami-0aa10b91c994a481d
6-
ap-southeast-1: ami-05698f82a71d681a5
7-
ap-southeast-2: ami-01da8b5a3a0212da1
8-
ca-central-1: ami-0845890c227805aeb
9-
eu-central-1: ami-54cffcbf
10-
eu-west-1: ami-08cb4b06d393675b0
11-
eu-west-2: ami-0cb0bfe1b8e796cd7
12-
eu-west-3: ami-0d277eafd4f569bc7
13-
sa-east-1: ami-056a9e6c13067d81f
14-
us-east-1: ami-0f4de43b53d2f8210
15-
us-east-2: ami-00c76d9774b0e366b
16-
us-west-1: ami-0cf41903fbdc094cc
17-
us-west-2: ami-03eee80fee70a432d
2+
ap-northeast-1: ami-05468a90639fdc483
3+
ap-northeast-2: ami-0b4d5a4a999581db1
4+
ap-northeast-3: ami-0594d5d373771f10a
5+
ap-south-1: ami-0ec7be770210af7c0
6+
ap-southeast-1: ami-02181eb4bbe285f28
7+
ap-southeast-2: ami-03199596cd474bb05
8+
ca-central-1: ami-099a5f4b65d56215e
9+
eu-central-1: ami-00e39ce170dbd6e25
10+
eu-west-1: ami-059b3db381c18305a
11+
eu-west-2: ami-0df738bfb4cf98f4e
12+
eu-west-3: ami-0b1472bf5fed029bd
13+
sa-east-1: ami-0a390e1998fb6b22f
14+
us-east-1: ami-0fd6854902340b407
15+
us-east-2: ami-04fc90a3f60cb3dc7
16+
us-west-1: ami-0054acc8361046ccc
17+
us-west-2: ami-01382f63e2667a7d1
1818
# centos6
19-
ap-northeast-1: ami-04d400f3c012a86ae
20-
ap-northeast-2: ami-068f5c3e07b48f123
21-
ap-northeast-3: ami-094d5e2e854fb015e
22-
ap-south-1: ami-0c8a6bf281179c3ba
23-
ap-southeast-1: ami-09555649a6bee7b69
24-
ap-southeast-2: ami-0610ffef47d7427d9
25-
ca-central-1: ami-0a36ee35b01f0e7c5
26-
eu-central-1: ami-89b38062
27-
eu-west-1: ami-00900f4e20bdb9f6d
28-
eu-west-2: ami-092aee04074dfd1f4
29-
eu-west-3: ami-042907d2cd70ecb40
30-
sa-east-1: ami-09d0f784c22548994
31-
us-east-1: ami-090b5303b54f5b35a
32-
us-east-2: ami-036cfbf5fc84c861e
33-
us-west-1: ami-0cc517b5b49ed6862
34-
us-west-2: ami-0e1ae8c0ca706fe64
19+
ap-northeast-1: ami-0603daa665c23cf74
20+
ap-northeast-2: ami-06ddec14c10c7de14
21+
ap-northeast-3: ami-0e718e0794e781ead
22+
ap-south-1: ami-043871a624a63c4b3
23+
ap-southeast-1: ami-07df16800a8f39379
24+
ap-southeast-2: ami-09b23d993fbc703d9
25+
ca-central-1: ami-0af06655a7341c2b5
26+
eu-central-1: ami-0362d5eb8ec477a30
27+
eu-west-1: ami-04c68c9303ee0165c
28+
eu-west-2: ami-0d3a080fd047d6f03
29+
eu-west-3: ami-0ce8fcafcd4cb66ba
30+
sa-east-1: ami-010873231de6443db
31+
us-east-1: ami-0051f4828527649d0
32+
us-east-2: ami-0a585da16a01304bb
33+
us-west-1: ami-0fcbc3afb66cfcffd
34+
us-west-2: ami-0430c74956ce8e41a
3535
# centos7
36-
ap-northeast-1: ami-0906ec2a1fce4fe7a
37-
ap-northeast-2: ami-098685fc947384e15
38-
ap-northeast-3: ami-07d36e7c754056e76
39-
ap-south-1: ami-0fce8c70d048719f4
40-
ap-southeast-1: ami-030771765a1101265
41-
ap-southeast-2: ami-0930016c10f90c7f0
42-
ca-central-1: ami-05652bb89f388a076
43-
eu-central-1: ami-dbc0f330
44-
eu-west-1: ami-0433c843433f06547
45-
eu-west-2: ami-07080ddf1e2406ca2
46-
eu-west-3: ami-062bd0a49558d0ba0
47-
sa-east-1: ami-005a0e54c37bc2a7b
48-
us-east-1: ami-01a681672ca8e9de1
49-
us-east-2: ami-07af67d83c0ae927c
50-
us-west-1: ami-00f4867c7e867784b
51-
us-west-2: ami-03ac1fbbf78947521
36+
ap-northeast-1: ami-03e99430742e7d834
37+
ap-northeast-2: ami-0a3ad3da5f45318a4
38+
ap-northeast-3: ami-0804a0d2dcf1e675f
39+
ap-south-1: ami-06b1a64ab30690802
40+
ap-southeast-1: ami-06eec4db7a3965f04
41+
ap-southeast-2: ami-0ab1def1c27a54ada
42+
ca-central-1: ami-089b3d6d4ef8c5772
43+
eu-central-1: ami-0842b79de396801b5
44+
eu-west-1: ami-019ecc5629a990951
45+
eu-west-2: ami-03e914c8e1b836bcf
46+
eu-west-3: ami-099b3883ce5e219b3
47+
sa-east-1: ami-0edbfab1cbd73ac82
48+
us-east-1: ami-00976a3c38aaac1a2
49+
us-east-2: ami-0f7dbb8d94e96b0ab
50+
us-west-1: ami-0fae379328b9061bc
51+
us-west-2: ami-0df85f5bc2d980e57
5252
# ubuntu1404
53-
ap-northeast-1: ami-04a90ea564e67f222
54-
ap-northeast-2: ami-0255a27fa98c0528f
55-
ap-northeast-3: ami-0cca427720a003215
56-
ap-south-1: ami-014f89aad9256d002
57-
ap-southeast-1: ami-0ce7dce420b05943b
58-
ap-southeast-2: ami-0ea64377e3b3b90df
59-
ca-central-1: ami-0cd24474b7cea7208
60-
eu-central-1: ami-7ab18291
61-
eu-west-1: ami-0e1dae876983c1547
62-
eu-west-2: ami-0ea3003a9feecc513
63-
eu-west-3: ami-0605f0c49b21107f6
64-
sa-east-1: ami-09657aae9df227834
65-
us-east-1: ami-063f3448775e0f9eb
66-
us-east-2: ami-0fc2efe14121a0f34
67-
us-west-1: ami-0c9cdda5cdea561c3
68-
us-west-2: ami-0bf2e2047ba8e44f2
53+
ap-northeast-1: ami-068214c5cfb518070
54+
ap-northeast-2: ami-0d55e5524b8536518
55+
ap-northeast-3: ami-0ad3400658fbc51fa
56+
ap-south-1: ami-0b54a1bd3d82929e6
57+
ap-southeast-1: ami-0d3382bea35764ad2
58+
ap-southeast-2: ami-0a2a8aa487ce39e8c
59+
ca-central-1: ami-0bc510154aa82211d
60+
eu-central-1: ami-0174c3f5501fc441b
61+
eu-west-1: ami-01848c6ae1a9c6460
62+
eu-west-2: ami-0b867b5579d0f7a08
63+
eu-west-3: ami-0e8f93d19635c5d49
64+
sa-east-1: ami-048422e42509a1596
65+
us-east-1: ami-0ba2fcbf9fa378762
66+
us-east-2: ami-05aea9ea89d577194
67+
us-west-1: ami-0089ace30f2612d13
68+
us-west-2: ami-06142a55749b7912b
6969
# ubuntu1604
70-
ap-northeast-1: ami-0b98c32fcc2c04bc2
71-
ap-northeast-2: ami-0dc1b8292d6a0ab0b
72-
ap-northeast-3: ami-0681a1857c07f6497
73-
ap-south-1: ami-05247ccd8ba04d440
74-
ap-southeast-1: ami-0e2b3651fe0a5734f
75-
ap-southeast-2: ami-0ee926ceddd54fc92
76-
ca-central-1: ami-01d71e35696000851
77-
eu-central-1: ami-dec0f335
78-
eu-west-1: ami-075d0841a0892ca5c
79-
eu-west-2: ami-06fa81f4e8255415a
80-
eu-west-3: ami-0fbfe76a8613c0d41
81-
sa-east-1: ami-033feb8d267b3a76e
82-
us-east-1: ami-003db261b3fbed1e3
83-
us-east-2: ami-05d8e0d6e52ecd2ed
84-
us-west-1: ami-0cd5cc8977ef144a5
85-
us-west-2: ami-0d3a3ff36f97c7ba4
70+
ap-northeast-1: ami-03f6879ede5f51a6f
71+
ap-northeast-2: ami-0036ef722f2d0a331
72+
ap-northeast-3: ami-0a8db47e6bc6f585b
73+
ap-south-1: ami-08870f6ce8227e90f
74+
ap-southeast-1: ami-04950204e84f8bf64
75+
ap-southeast-2: ami-02b4175018a85c03d
76+
ca-central-1: ami-04a4a63323b55af6e
77+
eu-central-1: ami-089e9903d9c3bee1b
78+
eu-west-1: ami-033b9190bab9d42aa
79+
eu-west-2: ami-049d2247a1c3d582c
80+
eu-west-3: ami-09c4322a65746f77b
81+
sa-east-1: ami-0740b75b4caaa3b77
82+
us-east-1: ami-05790a6a634720a0d
83+
us-east-2: ami-0a0fcd1219e40a8f5
84+
us-west-1: ami-056472d51cf2fed45
85+
us-west-2: ami-0702d59e57ada76b8

cli/cfncluster/cfncluster.py

+80-3
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
1010
# or in the "LICENSE.txt" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
1111
# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions and
1212
# limitations under the License.
13-
1413
from builtins import str
1514
import sys
1615
import time
1716
import logging
1817
import boto3
18+
import os
1919
from botocore.exceptions import ClientError
2020

2121
from . import cfnconfig
@@ -277,6 +277,31 @@ def poll_master_server_state(stack_name, config):
277277

278278
return state
279279

280+
def get_master_server_ip(stack_name, config):
281+
ec2 = boto3.client('ec2', region_name=config.region,
282+
aws_access_key_id=config.aws_access_key_id,
283+
aws_secret_access_key=config.aws_secret_access_key)
284+
285+
master_id = get_master_server_id(stack_name, config)
286+
287+
try:
288+
instance = ec2.describe_instances(InstanceIds=[master_id]) \
289+
.get('Reservations')[0] \
290+
.get('Instances')[0]
291+
ip_address = instance.get('PublicIpAddress')
292+
state = instance.get('State').get('Name')
293+
if state != 'running' or ip_address is None:
294+
logger.info("MasterServer: %s\nCannot get ip address." % state.upper)
295+
sys.exit(1)
296+
return ip_address
297+
except ClientError as e:
298+
logger.critical(e.response.get('Error').get('Message'))
299+
sys.stdout.flush()
300+
sys.exit(1)
301+
except KeyboardInterrupt:
302+
logger.info('\nExiting...')
303+
sys.exit(0)
304+
280305
def get_ec2_instances(stack, config):
281306
cfn = boto3.client('cloudformation', region_name=config.region,
282307
aws_access_key_id=config.aws_access_key_id,
@@ -346,6 +371,56 @@ def instances(args):
346371
for instance in instances:
347372
print('%s %s' % (instance[0],instance[1]))
348373

374+
def get_head_user(parameters, template):
375+
mappings = template.get("TemplateBody") \
376+
.get("Mappings") \
377+
.get("OSFeatures")
378+
base_os =[i.get('ParameterValue') for i in parameters if i.get('ParameterKey') == "BaseOS"][0]
379+
return mappings.get(base_os).get("User")
380+
381+
def command(args, extra_args):
382+
stack = ('cfncluster-' + args.cluster_name)
383+
config = cfnconfig.CfnClusterConfig(args)
384+
if args.command in config.aliases:
385+
config_command = config.aliases[args.command]
386+
else:
387+
config_command = "ssh {CFN_USER}@{MASTER_IP} {ARGS}"
388+
389+
cfn = boto3.client('cloudformation', region_name=config.region,
390+
aws_access_key_id=config.aws_access_key_id,
391+
aws_secret_access_key=config.aws_secret_access_key)
392+
try:
393+
status = cfn.describe_stacks(StackName=stack).get("Stacks")[0].get('StackStatus')
394+
invalid_status = ['DELETE_COMPLETE', 'DELETE_IN_PROGRESS']
395+
if status in invalid_status:
396+
logger.info("Stack status: %s. Cannot SSH while in %s" % (status, ' or '.join(invalid_status)))
397+
sys.exit(1)
398+
ip = get_master_server_ip(stack, config)
399+
stack_result = cfn.describe_stacks(StackName=stack).get('Stacks')[0]
400+
template = cfn.get_template(StackName=stack)
401+
username = get_head_user(stack_result.get('Parameters'), template)
402+
403+
try:
404+
from shlex import quote as cmd_quote
405+
except ImportError:
406+
from pipes import quote as cmd_quote
407+
408+
# build command
409+
cmd = config_command.format(CFN_USER=username, MASTER_IP=ip, ARGS=' '.join(cmd_quote(str(e)) for e in extra_args))
410+
411+
# run command
412+
if not args.dryrun:
413+
os.system(cmd)
414+
else:
415+
logger.info(cmd)
416+
except ClientError as e:
417+
logger.critical(e.response.get('Error').get('Message'))
418+
sys.stdout.flush()
419+
sys.exit(1)
420+
except KeyboardInterrupt:
421+
logger.info('\nExiting...')
422+
sys.exit(0)
423+
349424
def status(args):
350425
stack = ('cfncluster-' + args.cluster_name)
351426
config = cfnconfig.CfnClusterConfig(args)
@@ -406,9 +481,12 @@ def delete(args):
406481
aws_secret_access_key=config.aws_secret_access_key)
407482

408483
try:
484+
# delete_stack does not raise an exception if stack does not exist
485+
# Use describe_stacks to explicitly check if the stack exists
486+
cfn.describe_stacks(StackName=stack)
409487
cfn.delete_stack(StackName=stack)
410-
status = cfn.describe_stacks(StackName=stack).get("Stacks")[0].get('StackStatus')
411488
saw_update = True
489+
status = cfn.describe_stacks(StackName=stack).get("Stacks")[0].get('StackStatus')
412490
sys.stdout.write('\rStatus: %s' % status)
413491
sys.stdout.flush()
414492
logger.debug('Status: %s' % status)
@@ -439,4 +517,3 @@ def delete(args):
439517
except KeyboardInterrupt:
440518
logger.info('\nExiting...')
441519
sys.exit(0)
442-

cli/cfncluster/cfnconfig.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def __init__(self, args):
5252
__args_func = self.args.func.__name__
5353

5454
# Determine config file name based on args or default
55-
if args.config_file is not None:
55+
if hasattr(args, 'config_file') and args.config_file is not None:
5656
self.__config_file = args.config_file
5757
else:
5858
self.__config_file = os.path.expanduser(os.path.join('~', '.cfncluster', 'config'))
@@ -76,7 +76,7 @@ def __init__(self, args):
7676

7777
# Determine the EC2 region to used used or default to us-east-1
7878
# Order is 1) CLI arg 2) AWS_DEFAULT_REGION env 3) Config file 4) us-east-1
79-
if args.region:
79+
if hasattr(args, 'region') and args.region:
8080
self.region = args.region
8181
else:
8282
if os.environ.get('AWS_DEFAULT_REGION'):
@@ -213,6 +213,10 @@ def __init__(self, args):
213213
self.parameters.append((self.__vpc_options.get(key)[0],__temp__))
214214
except configparser.NoOptionError:
215215
pass
216+
except configparser.NoSectionError:
217+
print("ERROR: VPC section [%s] used in [%s] section is not defined"
218+
% (self.__vpc_section, self.__cluster_section))
219+
sys.exit(1)
216220

217221
# Dictionary list of all cluster section options
218222
self.__cluster_options = dict(cluster_user=('ClusterUser', None), compute_instance_type=('ComputeInstanceType',None),
@@ -334,6 +338,13 @@ def __init__(self, args):
334338
except AttributeError:
335339
pass
336340

341+
# handle aliases
342+
self.aliases = {}
343+
self.__alias_section = 'aliases'
344+
if __config.has_section(self.__alias_section):
345+
for alias in __config.options(self.__alias_section):
346+
self.aliases[alias] = __config.get(self.__alias_section, alias)
347+
337348
# Handle extra parameters supplied on command-line
338349
try:
339350
if self.args.extra_parameters is not None:

0 commit comments

Comments
 (0)