Skip to content
This repository has been archived by the owner on Sep 9, 2022. It is now read-only.

Commit

Permalink
Merge pull request #332 from uberblah/sns
Browse files Browse the repository at this point in the history
SNS Support
  • Loading branch information
dtan4 authored Jun 14, 2017
2 parents 918540b + 23e1a32 commit 8061079
Show file tree
Hide file tree
Showing 10 changed files with 440 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ Commands:
terraforming s3 # S3
terraforming sg # Security Group
terraforming sn # Subnet
terraforming snst # SNS Topic
terraforming snss # SNS Subscription
terraforming sqs # SQS
terraforming vgw # VPN Gateway
terraforming vpc # VPC
Expand Down
2 changes: 2 additions & 0 deletions lib/terraforming.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,5 @@
require "terraforming/resource/sqs"
require "terraforming/resource/vpc"
require "terraforming/resource/vpn_gateway"
require "terraforming/resource/sns_topic"
require "terraforming/resource/sns_topic_subscription"
10 changes: 10 additions & 0 deletions lib/terraforming/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,16 @@ def vgw
execute(Terraforming::Resource::VPNGateway, options)
end

desc "snst", "SNS Topic"
def snst
execute(Terraforming::Resource::SNSTopic, options)
end

desc "snss", "SNS Subscription"
def snss
execute(Terraforming::Resource::SNSTopicSubscription, options)
end

private

def configure_aws(options)
Expand Down
75 changes: 75 additions & 0 deletions lib/terraforming/resource/sns_topic.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
module Terraforming
module Resource
class SNSTopic
include Terraforming::Util

def self.tf(client: Aws::SNS::Client.new)
self.new(client).tf
end

def self.tfstate(client: Aws::SNS::Client.new)
self.new(client).tfstate
end

def initialize(client)
@client = client
end

def tf
apply_template(@client, "tf/sns_topic")
end

def tfstate
topics.inject({}) do |resources, topic|
attributes = {
"name" => module_name_of(topic),
"id" => topic["TopicArn"],
"arn" => topic["TopicArn"],
"display_name" => topic["DisplayName"],
"policy" => topic.key?("Policy") ? topic["Policy"] : "",
"delivery_policy" => topic.key?("DeliveryPolicy") ? topic["DeliveryPolicy"] : ""
}
resources["aws_sns_topic.#{module_name_of(topic)}"] = {
"type" => "aws_sns_topic",
"primary" => {
"id" => topic["TopicArn"],
"attributes" => attributes
}
}

resources
end
end

private

def topics
topic_arns.map do |topic_arn|
attributes = @client.get_topic_attributes({
topic_arn: topic_arn,
}).attributes
attributes["TopicArn"] = topic_arn
attributes
end
end

def topic_arns
token = ""
arns = []

loop do
resp = @client.list_topics(next_token: token)
arns += resp.topics.map(&:topic_arn).flatten
token = resp.next_token
break if token.nil?
end

arns
end

def module_name_of(topic)
normalize_module_name(topic["TopicArn"].split(":").last)
end
end
end
end
83 changes: 83 additions & 0 deletions lib/terraforming/resource/sns_topic_subscription.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
module Terraforming
module Resource
class SNSTopicSubscription
include Terraforming::Util

def self.tf(client: Aws::SNS::Client.new)
self.new(client).tf
end

def self.tfstate(client: Aws::SNS::Client.new)
self.new(client).tfstate
end

def initialize(client)
@client = client
end

def tf
apply_template(@client, "tf/sns_topic_subscription")
end

def tfstate
subscriptions.reject { |x| x["Protocol"].include?("email") }
.inject({}) do |resources, subscription|
attributes = {
"id" => subscription["SubscriptionArn"],
"topic_arn" => subscription["TopicArn"],
"protocol" => subscription["Protocol"],
"endpoint" => subscription["Endpoint"],
"raw_message_delivery" =>
subscription.key?("RawMessageDelivery") ? subscription["RawMessageDelivery"] : "false",
"confirmation_timeout_in_minutes" =>
subscription.key?("ConfirmationTimeoutInMinutes") ? subscription["ConfirmationTimeoutInMinutes"] : "1",
"endpoint_auto_confirms" =>
subscription.key?("EndpointAutoConfirms") ? subscription["EndpointAutoConfirms"] : "false"
}
resources["aws_sns_topic_subscription.#{module_name_of(subscription)}"] = {
"type" => "aws_sns_topic_subscription",
"primary" => {
"id" => subscription["SubscriptionArn"],
"attributes" => attributes
}
}

resources
end
end

private

def subscriptions
subscription_arns.map do |subscription_arn|
# check explicitly for an issue with some subscriptions that returns ARN=PendingConfirmation
next if subscription_arn == "PendingConfirmation"

attributes = @client.get_subscription_attributes({
subscription_arn: subscription_arn,
}).attributes
attributes["SubscriptionArn"] = subscription_arn
attributes
end.compact
end

def subscription_arns
token = ""
arns = []

loop do
resp = @client.list_subscriptions(next_token: token)
arns += resp.subscriptions.map(&:subscription_arn).flatten
token = resp.next_token
break if token.nil?
end

arns
end

def module_name_of(subscription)
normalize_module_name(subscription["SubscriptionArn"].split(":").last)
end
end
end
end
17 changes: 17 additions & 0 deletions lib/terraforming/template/tf/sns_topic.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<% topics.each do |topic| -%>
resource "aws_sns_topic" "<%= module_name_of(topic) %>" {
name = "<%= module_name_of(topic) %>"
display_name = "<%= topic["DisplayName"] %>"
<% if topic.key? "Policy" -%>
policy = <<POLICY
<%= prettify_policy(topic["Policy"], unescape: true) %>
POLICY
<% end -%>
<% if topic.key? "DeliveryPolicy" -%>
delivery_policy = <<POLICY
<%= prettify_policy(topic["DeliveryPolicy"], unescape: true) %>
POLICY
<% end -%>
}

<% end -%>
23 changes: 23 additions & 0 deletions lib/terraforming/template/tf/sns_topic_subscription.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<% subscriptions.each do |subscription| -%>
<% if subscription["Protocol"].include?("email") -%>
/*
<% end -%>
resource "aws_sns_topic_subscription" "<%= module_name_of(subscription) %>" {
topic_arn = "<%= subscription["TopicArn"] %>"
protocol = "<%= subscription["Protocol"] %>"
endpoint = "<%= subscription["Endpoint"] %>"
<% if subscription.key? "RawMessageDelivery" -%>
raw_message_delivery = "<%= subscription["RawMessageDelivery"] %>"
<% end -%>
<% if subscription.key? "ConfirmationTimeoutInMinutes" %>
confirmation_timeout_in_minutes = "<%= subscription["ConfirmationTimeoutInMinutes"] %>"
<% end -%>
<% if subscription.key? "EndpointAutoConfirms" %>
endpoint_auto_confirms = "<%= subscription["EndpointAutoConfirms"] %>"
<% end -%>
}
<% if subscription["Protocol"].include?("email") -%>
*/
<% end -%>

<% end -%>
14 changes: 14 additions & 0 deletions spec/lib/terraforming/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,20 @@ module Terraforming

it_behaves_like "CLI examples"
end

describe "snst" do
let(:klass) { Terraforming::Resource::SNSTopic }
let(:command) { :snst }

it_behaves_like "CLI examples"
end

describe "snss" do
let(:klass) { Terraforming::Resource::SNSTopicSubscription }
let(:command) { :snss }

it_behaves_like "CLI examples"
end
end

context "flush to stdout" do
Expand Down
117 changes: 117 additions & 0 deletions spec/lib/terraforming/resource/sns_topic_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
require "spec_helper"

module Terraforming
module Resource
describe SNSTopic do
let(:client) do
Aws::SNS::Client.new(stub_responses: true)
end

let(:topics) do
[
Aws::SNS::Types::Topic.new(topic_arn: "arn:aws:sns:us-west-2:012345678901:topicOfFanciness"),
]
end

let(:attributes) do
{
"SubscriptionsConfirmed" => "1",
"DisplayName" => "topicOfFancinessDisplayName",
"SubscriptionsDeleted" => "0",
"EffectiveDeliveryPolicy" => "{\"http\":{\"defaultHealthyRetryPolicy\":{\"minDelayTarget\":2,\"maxDelayTarget\":20,\"numRetries\":12,\"numMaxDelayRetries\":0,\"numNoDelayRetries\":0,\"numMinDelayRetries\":12,\"backoffFunction\":\"linear\"},\"disableSubscriptionOverrides\":false}}",
"Owner" => "012345678901",
"Policy" => "{\"Version\":\"2008-10-17\",\"Id\":\"__default_policy_ID\",\"Statement\":[{\"Sid\":\"__default_statement_ID\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"*\"},\"Action\":[\"SNS:GetTopicAttributes\",\"SNS:SetTopicAttributes\",\"SNS:AddPermission\",\"SNS:RemovePermission\",\"SNS:DeleteTopic\",\"SNS:Subscribe\",\"SNS:ListSubscriptionsByTopic\",\"SNS:Publish\",\"SNS:Receive\"],\"Resource\":\"arn:aws:sns:us-west-2:012345678901:topicOfFanciness\",\"Condition\":{\"StringEquals\":{\"AWS:SourceOwner\":\"012345678901\"}}}]}",
"DeliveryPolicy" => "{\"http\":{\"defaultHealthyRetryPolicy\":{\"minDelayTarget\":2,\"maxDelayTarget\":20,\"numRetries\":12,\"numMaxDelayRetries\":0,\"numNoDelayRetries\":0,\"numMinDelayRetries\":12,\"backoffFunction\":\"linear\"},\"disableSubscriptionOverrides\":false}}",
"TopicArn" => "arn:aws:sns:us-west-2:012345678901:topicOfFanciness",
"SubscriptionsPending" => "0"
}
end

before do
client.stub_responses(:list_topics, topics: topics)
client.stub_responses(:get_topic_attributes, attributes: attributes)
end

describe ".tf" do
it "should generate tf" do
expect(described_class.tf(client: client)).to eq <<-EOS
resource "aws_sns_topic" "topicOfFanciness" {
name = "topicOfFanciness"
display_name = "topicOfFancinessDisplayName"
policy = <<POLICY
{
"Version": "2008-10-17",
"Id": "__default_policy_ID",
"Statement": [
{
"Sid": "__default_statement_ID",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"SNS:GetTopicAttributes",
"SNS:SetTopicAttributes",
"SNS:AddPermission",
"SNS:RemovePermission",
"SNS:DeleteTopic",
"SNS:Subscribe",
"SNS:ListSubscriptionsByTopic",
"SNS:Publish",
"SNS:Receive"
],
"Resource": "arn:aws:sns:us-west-2:012345678901:topicOfFanciness",
"Condition": {
"StringEquals": {
"AWS:SourceOwner": "012345678901"
}
}
}
]
}
POLICY
delivery_policy = <<POLICY
{
"http": {
"defaultHealthyRetryPolicy": {
"minDelayTarget": 2,
"maxDelayTarget": 20,
"numRetries": 12,
"numMaxDelayRetries": 0,
"numNoDelayRetries": 0,
"numMinDelayRetries": 12,
"backoffFunction": "linear"
},
"disableSubscriptionOverrides": false
}
}
POLICY
}
EOS
end
end

describe ".tfstate" do
it "should generate tfstate" do
expect(described_class.tfstate(client: client)).to eq({
"aws_sns_topic.topicOfFanciness" => {
"type" => "aws_sns_topic",
"primary" => {
"id" => "arn:aws:sns:us-west-2:012345678901:topicOfFanciness",
"attributes" => {
"name" => "topicOfFanciness",
"id" => "arn:aws:sns:us-west-2:012345678901:topicOfFanciness",
"arn" => "arn:aws:sns:us-west-2:012345678901:topicOfFanciness",
"display_name" => "topicOfFancinessDisplayName",
"policy" => "{\"Version\":\"2008-10-17\",\"Id\":\"__default_policy_ID\",\"Statement\":[{\"Sid\":\"__default_statement_ID\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"*\"},\"Action\":[\"SNS:GetTopicAttributes\",\"SNS:SetTopicAttributes\",\"SNS:AddPermission\",\"SNS:RemovePermission\",\"SNS:DeleteTopic\",\"SNS:Subscribe\",\"SNS:ListSubscriptionsByTopic\",\"SNS:Publish\",\"SNS:Receive\"],\"Resource\":\"arn:aws:sns:us-west-2:012345678901:topicOfFanciness\",\"Condition\":{\"StringEquals\":{\"AWS:SourceOwner\":\"012345678901\"}}}]}",
"delivery_policy" => "{\"http\":{\"defaultHealthyRetryPolicy\":{\"minDelayTarget\":2,\"maxDelayTarget\":20,\"numRetries\":12,\"numMaxDelayRetries\":0,\"numNoDelayRetries\":0,\"numMinDelayRetries\":12,\"backoffFunction\":\"linear\"},\"disableSubscriptionOverrides\":false}}"
},
},
}
})
end
end
end
end
end
Loading

0 comments on commit 8061079

Please sign in to comment.