Skip to content

Commit

Permalink
Merge longaccess/buildbot:tags (PR #1067)
Browse files Browse the repository at this point in the history
  • Loading branch information
djmitche committed Apr 7, 2014
2 parents c1652f9 + a703f2e commit 00f32b0
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 1 deletion.
1 change: 1 addition & 0 deletions master/CREDITS
Expand Up @@ -254,6 +254,7 @@ Yoz Grahame
Zandr Milewski
Zellyn Hunter
Zooko Wilcox-O'Hearn
Konstantinos Koukopoulos

Name Unknown:
adam
Expand Down
5 changes: 4 additions & 1 deletion master/buildbot/buildslave/ec2.py
Expand Up @@ -59,7 +59,7 @@ def __init__(self, name, password, instance_type, ami=None,
max_builds=None, notify_on_missing=[], missing_timeout=60 * 20,
build_wait_timeout=60 * 10, properties={}, locks=None,
spot_instance=False, max_spot_price=1.6, volumes=[],
placement=None, price_multiplier=1.2):
placement=None, price_multiplier=1.2, tags={}):

AbstractLatentBuildSlave.__init__(
self, name, password, max_builds, notify_on_missing,
Expand Down Expand Up @@ -200,6 +200,7 @@ def __init__(self, name, password, instance_type, ami=None,
if elastic_ip is not None:
elastic_ip = self.conn.get_all_addresses([elastic_ip])[0]
self.elastic_ip = elastic_ip
self.tags = tags

def get_image(self):
if self.image is not None:
Expand Down Expand Up @@ -271,6 +272,8 @@ def _start_instance(self):
self.instance = reservation.instances[0]
instance_id, image_id, start_time = self._wait_for_instance(reservation)
if None not in [instance_id, image_id, start_time]:
if len(self.tags) > 0:
self.conn.create_tags(instance_id, self.tags)
return [instance_id, image_id, start_time]
else:
log.msg('%s %s failed to start instance %s (%s)' %
Expand Down
111 changes: 111 additions & 0 deletions master/buildbot/test/unit/test_buildslave_ec2.py
@@ -0,0 +1,111 @@
# This file is part of Buildbot. Buildbot is free software: you can
# redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, version 2.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Portions Copyright Buildbot Team Members
# Portions Copyright 2014 Longaccess private company

try:
from moto import mock_ec2
except ImportError:
mock_ec2 = lambda x: x
boto = None
else:
import boto
from buildbot.buildslave import ec2
from twisted.trial import unittest


class TestEC2LatentBuildSlave(unittest.TestCase):
ec2_connection = None

def setUp(self):
super(TestEC2LatentBuildSlave, self).setUp()
if boto is None:
raise unittest.SkipTest("moto not found")

def botoSetup(self):
c = boto.connect_ec2()
try:
c.create_key_pair('latent_buildbot_slave')
except NotImplementedError:
raise unittest.SkipTest("KeyPairs.create_key_pair not implemented"
" in this version of moto, please update.")
c.create_security_group('latent_buildbot_slave', 'the security group')
instance = c.run_instances('foo').instances[0]
c.create_image(instance.id, "foo", "bar")
c.terminate_instances([instance.id])
return c

@mock_ec2
def test_constructor_minimal(self):
c = self.botoSetup()
amis = c.get_all_images()
bs = ec2.EC2LatentBuildSlave('bot1', 'sekrit', 'm1.large',
identifier='publickey',
secret_identifier='privatekey',
ami=amis[0].id
)
self.assertEqual(bs.slavename, 'bot1')
self.assertEqual(bs.password, 'sekrit')
self.assertEqual(bs.instance_type, 'm1.large')
self.assertEqual(bs.ami, amis[0].id)

@mock_ec2
def test_constructor_tags(self):
c = self.botoSetup()
amis = c.get_all_images()
tags = {'foo': 'bar'}
bs = ec2.EC2LatentBuildSlave('bot1', 'sekrit', 'm1.large',
identifier='publickey',
secret_identifier='privatekey',
tags=tags,
ami=amis[0].id
)
self.assertEqual(bs.tags, tags)

@mock_ec2
def test_start_instance(self):
c = self.botoSetup()
amis = c.get_all_images()
bs = ec2.EC2LatentBuildSlave('bot1', 'sekrit', 'm1.large',
identifier='publickey',
secret_identifier='privatekey',
ami=amis[0].id
)
instance_id, image_id, start_time = bs._start_instance()
self.assertTrue(instance_id.startswith('i-'))
self.assertTrue(image_id.startswith('r-'))
self.assertTrue(start_time > 0)
instances = [i for i in c.get_only_instances()
if i.state != "terminated"]
self.assertEqual(len(instances), 1)
self.assertEqual(instances[0].id, instance_id)
self.assertEqual(instances[0].tags, {})

@mock_ec2
def test_start_instance_tags(self):
c = self.botoSetup()
amis = c.get_all_images()
tags = {'foo': 'bar'}
bs = ec2.EC2LatentBuildSlave('bot1', 'sekrit', 'm1.large',
identifier='publickey',
secret_identifier='privatekey',
tags=tags,
ami=amis[0].id
)
id, _, _ = bs._start_instance()
instances = [i for i in c.get_only_instances()
if i.state != "terminated"]
self.assertEqual(len(instances), 1)
self.assertEqual(instances[0].id, id)
self.assertEqual(instances[0].tags, tags)
12 changes: 12 additions & 0 deletions master/docs/manual/cfg-buildslaves.rst
Expand Up @@ -350,6 +350,18 @@ specify it in your configuration using the ``elastic_ip`` argument. ::
elastic_ip='208.77.188.166'
)]

One other way to configure a slave is by settings AWS tags. They can for example be used to
have a more restrictive security `IAM <http://aws.amazon.com/iam/>`_ policy. To get Buildbot to tag the latent slave
specify the tag keys and values in your configuration using the ``tags`` argument. ::

from buildbot.buildslave.ec2 import EC2LatentBuildSlave
c['slaves'] = [EC2LatentBuildSlave('bot1', 'sekrit', 'm1.large',
'ami-12345',
identifier='publickey',
secret_identifier='privatekey',
tags={'SomeTag': 'foo'}
)]

The :class:`EC2LatentBuildSlave` supports all other configuration from the standard
:class:`BuildSlave`. The ``missing_timeout`` and ``notify_on_missing`` specify how long
to wait for an EC2 instance to attach before considering the attempt to have
Expand Down
1 change: 1 addition & 0 deletions master/docs/relnotes/index.rst
Expand Up @@ -21,6 +21,7 @@ Features
* String parameter ``placement`` is appended to the ``region`` parameter, e.g. ``region='us-west-2', placement='b'``
will result in the spot request being placed in us-west-2b.
* Float parameter ``price_multiplier`` specifies the percentage bid above the 24-hour average spot price.
* Dict parameter ``tags`` specifies AWS tags as key/value pairs to be applied to new instances.

With spot_instance=True, an EC2LatentBuildSlave will attempt to create a spot instance with the provided spot
price, placement, and so on.
Expand Down

0 comments on commit 00f32b0

Please sign in to comment.