Skip to content

Commit

Permalink
Evaluate when running 'nixops send-keys' to make sure keys are updated.
Browse files Browse the repository at this point in the history
Move evaluation for send_keys to Deployment class.

Revert "Move evaluation for send_keys to Deployment class."

This reverts commit f727d25.

Evaluate when running 'nixops send-keys' to make sure keys are updated.

Move evaluation for send_keys to Deployment class.

Revert "Move evaluation for send_keys to Deployment class."

This reverts commit f727d25.

Revert "Evaluate when running 'nixops send-keys' to make sure keys are updated."

This reverts commit 7e14c4d.

adding AWS SNS resource

better naming

storing the subscribers

fixing descriptions

adding AWS sns to the manual

make sure to subscribe only if the subscriber doesn't exist already

exposing the arn, as it can be used in other deployment configs i.e an sns publish timer

Add support for provisioning Elastic File Systems

nixops info: Show IP address of EFS mount targets

Evaluate when running 'nixops send-keys' to make sure keys are updated.

Move evaluation for send_keys to Deployment class.

Revert "Move evaluation for send_keys to Deployment class."

This reverts commit f727d25.

Revert "Evaluate when running 'nixops send-keys' to make sure keys are updated."

This reverts commit 7e14c4d.

oops, screwed up during rebase

Typo

adding the ability to delete a subscription

add example of SNS topic

oops

remove copy paste

doh

storing the sns topics subscriptions as json in the statefile
  • Loading branch information
rbvermaa authored and AmineChikhaoui committed Oct 13, 2016
1 parent e8c315a commit 88bb0e3
Show file tree
Hide file tree
Showing 6 changed files with 276 additions and 2 deletions.
9 changes: 9 additions & 0 deletions doc/manual/manual.xml
Expand Up @@ -87,6 +87,15 @@
<xi:include href="sqs-queue-options.xml" />
</section>

<section>
<title>SNS Topics</title>
<para>An Amazon SNS topic is defined by setting
<literal>resources.snsTopics.<replaceable>name</replaceable></literal>
to an attribute set containing values for the following
options.</para>
<xi:include href="sns-topic-options.xml" />
</section>

<section>
<title>EC2 Keypairs</title>
<para>An Amazon EC2 keypair is defined by setting
Expand Down
20 changes: 20 additions & 0 deletions examples/sns-topic.nix
@@ -0,0 +1,20 @@
{ account
, region ? "us-east-1"
, description ? "SNS topic example"
, ...
}:
{
network.description = description;

resources.snsTopics.example-topic = {
name="sns-topic";
displayName="Nixops SNS topic";
accessKeyId = account;
subscriptions = [
{
protocol = "email";
endpoint = "amine@chikhaoui.tn";
}
];
inherit region; };
}
3 changes: 2 additions & 1 deletion nix/eval-machine-info.nix
Expand Up @@ -86,6 +86,7 @@ rec {
resources.sshKeyPairs = evalResources ./ssh-keypair.nix (zipAttrs resourcesByType.sshKeyPairs or []);

# Amazon resources
resources.snsTopics = evalResources ./sns-topic.nix (zipAttrs resourcesByType.snsTopics or []);
resources.sqsQueues = evalResources ./sqs-queue.nix (zipAttrs resourcesByType.sqsQueues or []);
resources.ec2KeyPairs = evalResources ./ec2-keypair.nix (zipAttrs resourcesByType.ec2KeyPairs or []);
resources.s3Buckets = evalResources ./s3-bucket.nix (zipAttrs resourcesByType.s3Buckets or []);
Expand Down Expand Up @@ -233,7 +234,7 @@ rec {

gce_default_bootstrap_images = flip mapAttrs' gce_deployments (name: depl:
let
gce = (scrubOptionValue depl).config.deployment.gce;
gce = (scrubOptionValue depl).config.deployment.gce;
images = {
"14.12" = "gs://nixos-cloud-images/nixos-14.12.471.1f09b77-x86_64-linux.raw.tar.gz";
"15.09" = "gs://nixos-cloud-images/nixos-15.09.425.7870f20-x86_64-linux.raw.tar.gz";
Expand Down
63 changes: 63 additions & 0 deletions nix/sns-topic.nix
@@ -0,0 +1,63 @@
{ config, lib, uuid, name, ... }:

with lib;

{

options = {

name = mkOption {
default = "charon-${uuid}-${name}";
type = types.str;
description = "Name of the SNS topic.";
};

region = mkOption {
type = types.str;
description = "AWS region.";
};

accessKeyId = mkOption {
type = types.str;
description = "The AWS Access Key ID.";
};

displayName = mkOption {
default = null;
type = types.nullOr (types.str);
description = "Display name of the topic";
};

policy = mkOption {
default = "";
type = types.str;
description = "Policy to apply to the SNS topic.";
};

subscriptions = mkOption {
type = types.listOf types.optionSet;
description = "List of subscriptions to apply to the topic.";
default = [];
options = {
protocol = mkOption {
default = null;
description = "The protocol to use.";
type = types.str;
};
endpoint = mkOption {
default = null;
description = "The endpoint to send data to.";
type = types.str;
};
};
};

arn = mkOption {
default = "";
type = types.str;
description = "Amazon Resource Name (ARN) of the SNS topic. This is set by NixOps.";
};

};

}
181 changes: 181 additions & 0 deletions nixops/resources/sns_topic.py
@@ -0,0 +1,181 @@
# -*- coding: utf-8 -*-

# Automatic provisioning of AWS SNS topics.

import boto
import boto.sns
import nixops.util
import nixops.resources
import nixops.ec2_utils
from xml.etree import ElementTree

class SNSTopicDefinition(nixops.resources.ResourceDefinition):
"""Definition of an SNS topic."""

@classmethod
def get_type(cls):
return "sns-topic"

@classmethod
def get_resource_type(cls):
return "snsTopics"

def __init__(self, xml):
nixops.resources.ResourceDefinition.__init__(self, xml)
self.topic_name = xml.find("attrs/attr[@name='name']/string").get("value")
self.access_key_id = xml.find("attrs/attr[@name='accessKeyId']/string").get("value")
self.region = xml.find("attrs/attr[@name='region']/string").get("value")
dn = xml.find("attrs/attr[@name='displayName']/string")
self.display_name = dn.get("value") if dn != None else None
self.policy = xml.find("attrs/attr[@name='policy']/string").get("value")
self.subscriptions = []
subscriptions = xml.findall("attrs/attr[@name='subscriptions']/list/attrs")
for subscription in subscriptions:
subscriber = {}
subscriber['protocol'] = subscription.find("attr[@name='protocol']/string").get("value")
subscriber['endpoint'] = subscription.find("attr[@name='endpoint']/string").get("value")
self.subscriptions.append(subscriber)

def show_type(self):
return "{0}".format(self.get_type())


class SNSTopicState(nixops.resources.ResourceState):
"""State of an SNS topic."""

state = nixops.util.attr_property("state", nixops.resources.ResourceState.MISSING, int)
topic_name = nixops.util.attr_property("ec2.topicName", None)
access_key_id = nixops.util.attr_property("ec2.accessKeyId", None)
display_name = nixops.util.attr_property("ec2.topicDisplayName", None)
region = nixops.util.attr_property("ec2.region", None)
policy = nixops.util.attr_property("ec2.topicPolicy", None)
arn = nixops.util.attr_property("ec2.topicARN", None)
subscriptions = nixops.util.attr_property("ec2.topicSubscriptions", [],'json')

@classmethod
def get_type(cls):
return "sns-topic"


def __init__(self, depl, name, id):
nixops.resources.ResourceState.__init__(self, depl, name, id)
self._conn = None


def show_type(self):
s = super(SNSTopicState, self).show_type()
if self.region: s = "{0} [{1}]".format(s, self.region)
return s


@property
def resource_id(self):
return self.topic_name

def prefix_definition(self, attr):
return {('resources', 'snsTopics'): attr}

def get_physical_spec(self):
return {'arn': self.arn}

def get_definition_prefix(self):
return "resources.snsTopics."


def connect(self):
if self._conn: return
assert self.region
(access_key_id, secret_access_key) = nixops.ec2_utils.fetch_aws_secret_key(self.access_key_id)
self._conn = boto.sns.connect_to_region(
region_name=self.region, aws_access_key_id=access_key_id, aws_secret_access_key=secret_access_key)


def _destroy(self):
if self.state != self.UP: return
self.connect()
self.log("destroying SNS topic ‘{0}’...".format(self.topic_name))
self._conn.delete_topic(self.arn)
with self.depl._db:
self.state = self.MISSING
self.topic_name = None
self.region = None
self.policy = None
self.arn = None

def topic_exists(self,arn):
return True


def create(self, defn, check, allow_reboot, allow_recreate):
self.access_key_id = defn.access_key_id or nixops.ec2_utils.get_access_key_id()
if not self.access_key_id:
raise Exception("please set ‘accessKeyId’, $EC2_ACCESS_KEY or $AWS_ACCESS_KEY_ID")

arn = self.arn
if self.state == self.UP and (self.topic_name != defn.topic_name or self.region != defn.region):
self.log("topic definition changed, recreating...")
self._destroy()
self._conn = None

self.region = defn.region
self.connect()

if self.arn == None:
self.log("creating SNS topic ‘{0}’...".format(defn.topic_name))
topic = self._conn.create_topic(defn.topic_name)
arn = topic.get('CreateTopicResponse').get('CreateTopicResult')['TopicArn']

if defn.display_name != None:
self._conn.set_topic_attributes(topic=arn,attr_name="DisplayName",attr_value=defn.display_name)

if defn.policy != "":
policy = self._conn.set_topic_attributes(topic=arn,attr_name="Policy",attr_value=defn.policy)

current_subscribers, current_subscriptions_arns = self.get_current_subscribers(arn=arn)

if len(defn.subscriptions) > 0:
for subscriber in defn.subscriptions:
protocol = subscriber['protocol']
endpoint = subscriber['endpoint']
if endpoint not in current_subscribers:
self.log("adding SNS subscriber with endpoint '{0}'...".format(endpoint))
self._conn.subscribe(topic=arn,protocol=protocol,endpoint=endpoint)

defn_endpoints = self.get_defn_endpoints(defn)
if len(defn_endpoints) > 0:
for subscriber_endpoint, subscriber_arn in current_subscriptions_arns.items():
if subscriber_endpoint not in defn_endpoints:
self.log("removing SNS subscriber with endpoint '{0}'...".format(subscriber_endpoint))
self._conn.unsubscribe(subscription=subscriber_arn)

with self.depl._db:
self.state = self.UP
self.topic_name = defn.topic_name
self.display_name = defn.display_name
self.policy = defn.policy
self.arn = arn
self.subscriptions = defn.subscriptions


def get_current_subscribers(self,arn):
response = self._conn.get_all_subscriptions_by_topic(topic=arn)
current_subscribers = response['ListSubscriptionsByTopicResponse']['ListSubscriptionsByTopicResult']['Subscriptions']
current_endpoints = []
current_subscriptions_arns = {}
if len(current_subscribers) > 0:
for subscriber in current_subscribers:
current_endpoints.append(subscriber['Endpoint'])
current_subscriptions_arns[subscriber['Endpoint']]=subscriber['SubscriptionArn']
return current_endpoints,current_subscriptions_arns

def get_defn_endpoints(self,defn):
defn_endpoints = []
if len(defn.subscriptions) > 0:
for subscriber in defn.subscriptions:
defn_endpoints.append(subscriber['endpoint'])
return defn_endpoints


def destroy(self, wipe=False):
self._destroy()
return True
2 changes: 1 addition & 1 deletion release.nix
Expand Up @@ -36,7 +36,7 @@ rec {
cp ${import ./doc/manual { revision = nixopsSrc.rev; }} doc/manual/machine-options.xml
${pkgs.lib.concatMapStrings (fn: ''
cp ${import ./doc/manual/resource.nix { revision = nixopsSrc.rev; module = ./nix + ("/" + fn + ".nix"); }} doc/manual/${fn}-options.xml
'') [ "ebs-volume" "sqs-queue" "ec2-keypair" "s3-bucket" "iam-role" "ssh-keypair" "ec2-security-group" "elastic-ip"
'') [ "ebs-volume" "sns-topic" "sqs-queue" "ec2-keypair" "s3-bucket" "iam-role" "ssh-keypair" "ec2-security-group" "elastic-ip"
"gce-disk" "gce-image" "gce-forwarding-rule" "gce-http-health-check" "gce-network"
"gce-static-ip" "gce-target-pool" "gse-bucket"
"azure-availability-set" "azure-blob-container" "azure-blob" "azure-directory"
Expand Down

0 comments on commit 88bb0e3

Please sign in to comment.