Creates a new server instance.  This call blocks until the server is
        created and available for normal use, or :attr:`timeout_s` has elapsed.

        :param str basename:  An identifier for the server.

        :param str server_tpl:  The name of the server template to use.

        :param str server_tpl_rev:  The revision of the server template to use.
            For ``HEAD``, set this to ``0``.

        :param str instance_type:  The name of an instance type.  E.g.
            ``m3.xlarge``.

        :param str ssh_key_name:  The name of the ssh key to inject into the
            target server's ``authorized_keys`` file.  The key must already
            have been registered in the RightScale datacenter
            (e.g. ``EC2 us-east-1``).

        :param tags:  Key-value pairs of arbitrary strings to use as *tags* for
            the server instance.
        :type tags:  :class:`Mapping`

        :param str availability_zone:  The name of the availability zone
            (a.k.a. datacenter in RightScale lingo) in which to place the
            server.

        :param list security_groups: The security groups to which this server
            should belong.

        :param provider_extras: Extra server instance attributes as defined in
            http://reference.rightscale.com/api1.5/resources/ResourceServers.html#create

        :rtype:  :class:`dict`

def define_server(
            self, basename, server_tpl, server_tpl_rev, instance_type,
            ssh_key_name, tags=None, availability_zone=None,
            security_groups=None, **provider_extras
            ):
        """
        Creates a new server instance.  This call blocks until the server is
        created and available for normal use, or :attr:`timeout_s` has elapsed.

        :param str basename:  An identifier for the server.

        :param str server_tpl:  The name of the server template to use.

        :param str server_tpl_rev:  The revision of the server template to use.
            For ``HEAD``, set this to ``0``.

        :param str instance_type:  The name of an instance type.  E.g.
            ``m3.xlarge``.

        :param str ssh_key_name:  The name of the ssh key to inject into the
            target server's ``authorized_keys`` file.  The key must already
            have been registered in the RightScale datacenter
            (e.g. ``EC2 us-east-1``).

        :param tags:  Key-value pairs of arbitrary strings to use as *tags* for
            the server instance.
        :type tags:  :class:`Mapping`

        :param str availability_zone:  The name of the availability zone
            (a.k.a. datacenter in RightScale lingo) in which to place the
            server.

        :param list security_groups: The security groups to which this server
            should belong.

        :param provider_extras: Extra server instance attributes as defined in
            http://reference.rightscale.com/api1.5/resources/ResourceServers.html#create

        :rtype:  :class:`dict`

        """
        log.info('Defining server %s...' % basename)
        self.basename = basename

        # required attributes
        tpl = find_exact(
                self.api.server_templates,
                name=server_tpl,
                revision=server_tpl_rev,
                )
        # ... the rightscale and aws apis allow you to spin up a server without
        #     a key, but let's not. we already assume you need ssh for ansible.
        sshkey = find_exact(
                self.cloud.ssh_keys,
                resource_uid=ssh_key_name,
                )
        data = {
                'server[deployment_href]': self.deployment.href,
                'server[instance][cloud_href]': self.cloud.href,
                'server[instance][server_template_href]': tpl.href,
                'server[instance][ssh_key_href]': sshkey.href,
                'server[name]': basename,
                }

        # optional attributes (i.e. you can set these to '' in bang configs)
        itype = find_exact(
                self.cloud.instance_types,
                name=instance_type,
                )
        if itype:
            data['server[instance][instance_type_href]'] = itype.href

        datacenter = find_exact(
                self.cloud.datacenters,
                name=availability_zone,
                )
        if datacenter:
            data['server[instance][datacenter_href]'] = datacenter.href

        secgroup_hrefs = []
        for n in security_groups:
            secgroup = find_exact(self.cloud.security_groups, name=n)
            if secgroup:
                secgroup_hrefs.append(secgroup.href)
        if secgroup_hrefs:
            data['server[instance][security_group_hrefs][]'] = secgroup_hrefs

        if provider_extras:
            # use a copy because the inbound provider_extras will be passed in again
            # when calling create_server()
            shallow_kwargs = provider_extras.copy()

            # defer all inputs until launch time
            shallow_kwargs.pop(A.rightscale.INPUTS, None)

            cloud_specific = shallow_kwargs.pop(A.rightscale.CLOUD_SPECIFIC, {})
            for k, v in cloud_specific.iteritems():
                data['server[instance][cloud_specific_attributes][%s]' % k] = v
            for k, v in shallow_kwargs.iteritems():
                data['server[instance][%s]' % k] = v

        try:
            response = self.api.client.post('/api/servers', data=data)
            server_href = response.headers['location']
        except HTTPError as e:
            log.error(
                    'Definition failed.  RightScale returned %d:\n%s'
                    % (e.response.status_code, e.response.content)
                    )
            raise

        # tag it!
        all_tags = [
                'ec2:role=%s' % self.basename,
                'ec2:stack=%s' % self.deployment.soul['name'],
                ]
        all_tags.extend(['ec2:%s=%s' % (k, v) for k, v in tags.items()])
        try:
            self.api.tags.multi_add(
                    data={
                        'resource_hrefs[]': [server_href],
                        'tags[]': all_tags,
                        }
                    )
        except HTTPError as e:
            log.error(
                    'Failed to tag server %s. RightScale returned %d:\n%s' % (
                        self.basename,
                        e.response.status_code,
                        e.response.content
                        )
                    )
            raise

        return server_href