Skip to content

Instantly share code, notes, and snippets.

@nitecoder
Last active August 29, 2015 13:57
Show Gist options
  • Select an option

  • Save nitecoder/9536584 to your computer and use it in GitHub Desktop.

Select an option

Save nitecoder/9536584 to your computer and use it in GitHub Desktop.

Revisions

  1. nitecoder renamed this gist Mar 13, 2014. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. nitecoder created this gist Mar 13, 2014.
    162 changes: 162 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,162 @@
    from starcluster.clustersetup import ClusterSetup
    from starcluster.logger import log
    import subprocess
    from starcluster import threadpool

    from boto.route53.connection import Route53Connection
    from boto.route53.connection import ResourceRecordSets

    class Route53Plugin(ClusterSetup):

    def __init__(self,
    zone_name,
    master_name_template,
    node_name_template,
    dry_run):
    """Parameters:
    zone_name - name of the Route53 zone in which to register A records
    master_name_template - register name for master based on this template
    node_name_template - register name for nodes based on this template
    dry_run - don't commit changes if True

    templates can use
    {alias} to substitute for node.alias
    {zone} to substitute for zone.name
    """
    self.zone_name = zone_name
    self.master_name_template = master_name_template
    self.node_name_template = node_name_template
    self.dry_run = dry_run
    self.conn = Route53Connection()
    log.info("route53_plugin: *********** init: DRY_RUN=%s" % dry_run)


    def run (self, nodes, master, user, user_shell, volumes):
    log.debug("route53_plugin: *********** run: %s", nodes)
    comment="Starcluster route53_plugin run for %s" % [n.alias for n in nodes]
    self._registerNodes(nodes, comment)

    # def on_restart(self, nodes, master, user, user_shell, volumes):
    # log.debug("route53_plugin: *********** run: %s", nodes)
    # comment="Starcluster route53_plugin run for %s" % [n.alias for n in nodes]
    # _registerNodes(nodes, comment)

    def on_add_node(self, node, nodes, master, user, user_shell, volumes):
    log.debug("route53_plugin: *********** add_node: %s", node)
    comment="Starcluster route53_plugin add_node %s" % node.alias
    self._registerNodes([node], comment)


    def on_remove_node(self, node, nodes, master, user, user_shell, volumes):
    log.debug("route53_plugin: *********** remove_node: %s", node)
    comment="Starcluster route53_plugin remove_node %s" % node.alias
    self._unregisterNodes([node], comment)

    def on_shutdown(self, nodes, master, user, user_shell, volumes):
    log.debug("route53_plugin: *********** shutdown: %s", nodes)
    comment="Starcluster route53_plugin shutdown %s" % [n.alias for n in nodes]
    self._unregisterNodes(nodes, comment)

    def _registerNodes(self, nodes, comment):
    changeSet = self._startChangeSet(comment)
    if changeSet == None:
    log.error("route53_plugin: *** unable to create change set")
    return

    for node in nodes:
    log.debug("route53_plugin: checking node %s (is_master %s)", node, node.is_master())
    if not node.is_master() and self.master_name_template:
    self._registerNode(changeSet, node, self.master_name_template)
    elif self.node_name_template:
    self._registerNode(changeSet, node, self.node_name_template)

    self._commitChangeSet(changeSet)


    def _unregisterNodes(self, nodes, comment):
    changeSet = self._startChangeSet(comment)
    if changeSet == None:
    log.error("route53_plugin: *** unable to create change set")
    return

    for node in nodes:
    log.debug("route53_plugin: checking node %s (is_master %s)", node, node.is_master())
    if not node.is_master() and self.master_name_template:
    self._unregisterNode(changeSet, node)
    elif self.node_name_template:
    self._unregisterNode(changeSet, node)

    self._commitChangeSet(changeSet)


    def _startChangeSet(self, comment=None):
    zone = self.conn.get_zone(self.zone_name)
    if not zone:
    log.error("route53_plugin: *** No zone %s, please create", self.zone_name)
    return None

    log.debug("route53_plugin: *** creating change set for zone %s (%s)", zone, comment)
    return ResourceRecordSets(self.conn, zone.id, comment=comment)


    def _commitChangeSet(self, changeSet):
    log.info("chef_plugin: *** Submitting to route53 %s", changeSet)
    if not changeSet.changes:
    log.debug("chef_plugin: empty change set - nothing to do")
    return

    if self.dry_run:
    log.warn("chef_plugin: DRY-RUN ONLY - not sending to route53")
    return

    return changeSet.commit()
    # TODO: consider waiting for request to be INSYNC

    def _unregisterNode(self, changeSet, node):
    hostname = node.tags.get('hostname', None)
    if not hostname:
    log.info("route53_plugin: *** not hostname tag, nothing to unregister for %s", node)
    return

    return self._unregisterHostName(changeSet, hostname)


    def _registerNode(self, changeSet, node, name_template):
    addr = node.ip_address #node.addr
    if not addr:
    addr = node.private_ip_address

    if not addr:
    log.error("route53_plugin: *** unable to obtain address for node %s", node)
    return

    name = name_template.format(
    alias=node.alias,
    zone=self.zone_name
    )

    if not name:
    log.error("route53_plugin: *** unable to obtain the name for node %s template %s", node, node_template)
    return

    node.add_tag('hostname', name)
    return self._registerHostName(changeSet, name, addr)


    def _unregisterHostName(self, changeSet, name):
    zone = self.conn.get_zone(self.zone_name)
    r = zone.get_a(name)
    if not r:
    log.warn("route53_plugin: *** no record found for name %s - nothing to unregister", name)
    return

    req = changeSet.add_change_record('DELETE', r)
    #log.info("route53_plugin: *** Deleting A record %s for %s", r, name)
    #zone.delete_a(name)


    def _registerHostName(self, changeSet, name, addr):
    req = changeSet.add_change(action='UPSERT', name=name, type='A', ttl=300)
    req.add_value(addr)