diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3fe5c34 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Rhythmic Technologies, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/cloudformation.yml.tpl b/cloudformation.yml.tpl new file mode 100644 index 0000000..e19ed62 --- /dev/null +++ b/cloudformation.yml.tpl @@ -0,0 +1,29 @@ +Resources: + ImageBuildComponent: + Type: AWS::ImageBuilder::Component + Properties: + Name: ${name} + Version: ${version} + %{~ if change_description != null ~} + ChangeDescription: ${change_description} + %{~ endif ~} + %{~ if description != null ~} + Description: ${description} + %{~ endif ~} + %{~ if kms_key_id != null ~} + KmsKeyId: ${kms_key_id} + %{~ endif ~} + Platform: ${platform} + Tags: + ${ indent(8, chomp(yamlencode(tags))) } + %{~ if uri != null ~} + Uri: ${uri} + %{~ endif ~} + %{~ if data != null ~} + Data: | + ${indent(8, data)} + %{~ endif ~} +Outputs: + ComponentArn: + Description: ARN of the created component + Value: !Ref "ImageBuildComponent" diff --git a/component.yml.tpl b/component.yml.tpl new file mode 100644 index 0000000..b4f5660 --- /dev/null +++ b/component.yml.tpl @@ -0,0 +1,44 @@ +name: ${name}-document +%{ if description != null ~} +description: ${description} +%{ endif ~} +schemaVersion: 1.0 +phases: + - name: build + steps: + - name: ansible-install + action: ExecuteBash + inputs: + commands: + # Install Ansible dependencies + - sudo yum install -y python python3 python-pip python3-pip git + # Enable Ansible repository + - sudo amazon-linux-extras enable ansible2 + # Install Ansible + - sudo yum install -y ansible + - name: get-playbook + action: ExecuteBash + inputs: + commands: + - git clone --depth 1 ${playbook_repo} + - name: run-playbook + action: ExecuteBash + inputs: + commands: + %{~ if playbook_dir != null ~} + - cd ${playbook_dir} + %{~ endif ~} + # Install playbook dependencies + - ansible-galaxy install -f -r requirements.yml || true + # Wait for cloud-init + - while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Waiting for cloud-init...'; sleep 1; done + # Run playbook + - ansible-playbook ${playbook_file} + - name: cleanup + action: ExecuteBash + inputs: + commands: + - sudo yum remove -y ansible + - sudo yum autoremove -y + - sudo rm -rf packer-generic-images + - sudo rm -rf ~/.ansible/roles /usr/share/anisble/roles /etc/ansible/roles diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..055321a --- /dev/null +++ b/main.tf @@ -0,0 +1,36 @@ +locals { + data = templatefile("${path.module}/component.yml.tpl", { + description = var.description + name = var.name + playbook_dir = var.playbook_dir + playbook_file = var.playbook_file + playbook_repo = var.playbook_repo + }) +} + +resource "aws_cloudformation_stack" "this" { + name = var.name + on_failure = "ROLLBACK" + timeout_in_minutes = var.cloudformation_timeout + + tags = merge( + var.tags, + { Name : "${var.name}-stack" } + ) + + template_body = templatefile("${path.module}/cloudformation.yml.tpl", { + change_description = var.change_description + data = local.data + description = var.description + kms_key_id = var.kms_key_id + name = var.name + platform = var.platform + uri = var.data_uri + version = var.component_version + + tags = merge( + var.tags, + { Name : var.name } + ) + }) +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..d5da9a4 --- /dev/null +++ b/outputs.tf @@ -0,0 +1,3 @@ +output "component_arn" { + value = aws_cloudformation_stack.this.outputs["ComponentArn"] +} diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..339ae93 --- /dev/null +++ b/variables.tf @@ -0,0 +1,68 @@ +variable "change_description" { + default = null + description = "description of changes since last version" + type = string +} + +variable "cloudformation_timeout" { + default = 10 + description = "How long to wait (in minutes) for CFN to apply before giving up" + type = number +} + +variable "component_version" { + description = "Version of the component" + type = string +} + +variable "data_uri" { + default = null + description = "Use this to override the component document with one at a particualar URL endpoint" + type = string +} + +variable "description" { + default = null + description = "description of component" + type = string +} + +variable "kms_key_id" { + default = null + description = "KMS key to use for encryption" + type = string +} + +variable "name" { + description = "name to use for component" + type = string +} + +# TODO: add validation +variable "platform" { + default = "Linux" + description = "platform of component (Linux or Windows)" + type = string +} + +variable "playbook_dir" { + default = null + description = "directory where playbook and requirements are found (if not root of repo)" + type = string +} + +variable "playbook_file" { + default = "provision.yml" + description = "path to playbook file, relative to `playbook_dir`" +} + +variable "playbook_repo" { + description = "git url for repo where ansible code lives" + type = string +} + +variable "tags" { + default = {} + description = "map of tags to use for CFN stack and component" + type = map(string) +}