-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 8214de1
Showing
13 changed files
with
340 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
Sbt plugin to upload app version to elastic beanstalk. | ||
This is very much a work in progress | ||
|
||
# Set up | ||
|
||
The following need to be set: | ||
|
||
``` | ||
ebSettings | ||
ebS3BucketName := "bucket-to-store-app-version" | ||
ebAppBundleSource := (stage in Docker).value // Source to bundle up | ||
//Defaults to eu-west-1 | ||
ebRegion := "region" | ||
ebDescription := "version description" | ||
//Defaults to application name | ||
ebAppName := "My First Elastic Beanstalk Application" | ||
//Default to application version | ||
ebVersion := "version" | ||
``` | ||
|
||
# TODO | ||
- Make auto plugin | ||
- Use version for `sbt-git` if active | ||
|
||
# Acknowledgements | ||
|
||
Project inspired by https://github.com/sqs/sbt-elasticbeanstalk and https://github.com/sbt/sbt-s3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
|
||
name := "sbt-eb" | ||
|
||
description := "Plugin for elastic beanstalk uploads" | ||
|
||
version := "0.1" | ||
|
||
organization := "com.frosforever" | ||
|
||
sbtPlugin := true | ||
|
||
libraryDependencies ++= Seq( | ||
"com.amazonaws" % "aws-java-sdk-s3" % "1.10.5.1", | ||
"com.amazonaws" % "aws-java-sdk-elasticbeanstalk" % "1.10.5.1" | ||
) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
sbt.version=0.13.8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import java.io.File | ||
|
||
import com.amazonaws._ | ||
import com.amazonaws.auth._ | ||
import com.amazonaws.event.{ProgressEvent, ProgressEventType, SyncProgressListener} | ||
import com.amazonaws.regions.Regions | ||
import com.amazonaws.services.elasticbeanstalk.AWSElasticBeanstalkClient | ||
import com.amazonaws.services.elasticbeanstalk.model.{CreateApplicationVersionRequest, DeleteApplicationVersionRequest, S3Location} | ||
import com.amazonaws.services.s3._ | ||
import com.amazonaws.services.s3.model.PutObjectRequest | ||
|
||
object ApplicationDeployer { | ||
def getEBClient(regionName: String) = { | ||
val credentials = new DefaultAWSCredentialsProviderChain | ||
val client = new AWSElasticBeanstalkClient(credentials, new ClientConfiguration().withProtocol(Protocol.HTTPS)) | ||
//Using the Fluent `withRegion` throws ClassCastException: com.amazonaws.services.elasticbeanstalk.AWSElasticBeanstalkClient cannot be cast to scala.runtime.Nothing$ | ||
client.configureRegion(Regions.fromName(regionName)) | ||
client | ||
} | ||
|
||
def deleteEbVersion(client: AWSElasticBeanstalkClient, applicationName: String, versionLabel: String) = { | ||
val request = new DeleteApplicationVersionRequest(applicationName, versionLabel).withDeleteSourceBundle(true) | ||
client.deleteApplicationVersion(request) | ||
} | ||
|
||
def createEbVersion(client: AWSElasticBeanstalkClient, applicationName: String, versionLabel: String, description: String, bundleS3Location: S3Location) = { | ||
//TODO: versionLabel between 1 and 100 chars without '/'. Should we modify it or just let it fail? | ||
val request = new CreateApplicationVersionRequest(applicationName, versionLabel). | ||
withSourceBundle(bundleS3Location). | ||
withDescription(description.take(199)) //Description max 200 chars | ||
client.createApplicationVersion(request) | ||
} | ||
} | ||
|
||
|
||
object BundleUploader { | ||
private def getS3Client = { | ||
val credentials = new DefaultAWSCredentialsProviderChain | ||
new AmazonS3Client(credentials, new ClientConfiguration().withProtocol(Protocol.HTTPS)) | ||
} | ||
|
||
def uploadBundle(bucket: String, bundle: File): S3Location = { | ||
uploadBundle(bucket, bundle, bundle.getName) | ||
} | ||
|
||
def uploadBundle(bucket: String, bundle: File, key: String): S3Location = { | ||
val request = new PutObjectRequest(bucket, key, bundle) | ||
request.setGeneralProgressListener(UploadProgressListener(bundle.length())) | ||
getS3Client.putObject(request) | ||
new S3Location(bucket, key) | ||
} | ||
|
||
private def progressBar(percent:Int) = { | ||
val b="==================================================" | ||
val s=" " | ||
val p=percent/2 | ||
val z:StringBuilder=new StringBuilder(80) | ||
z.append("\r[") | ||
z.append(b.substring(0,p)) | ||
if (p<50) {z.append(">"); z.append(s.substring(p))} | ||
z.append("] ") | ||
if (p<5) z.append(" ") | ||
if (p<50) z.append(" ") | ||
z.append(percent) | ||
z.append("% ") | ||
z.mkString | ||
} | ||
|
||
private case class UploadProgressListener(fileSize: Long) extends SyncProgressListener { | ||
var uploadedBytes = 0L | ||
|
||
override def progressChanged(progressEvent: ProgressEvent): Unit = { | ||
if (progressEvent.getEventType == ProgressEventType.REQUEST_BYTE_TRANSFER_EVENT || | ||
progressEvent.getEventType == ProgressEventType.RESPONSE_BYTE_TRANSFER_EVENT) { | ||
uploadedBytes = uploadedBytes + progressEvent.getBytesTransferred | ||
} | ||
print(progressBar(if (fileSize > 0) ((uploadedBytes * 100) / fileSize).toInt else 100)) | ||
if (progressEvent.getEventType == ProgressEventType.TRANSFER_COMPLETED_EVENT) | ||
println() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import java.io.File | ||
|
||
import com.amazonaws.services.elasticbeanstalk.AWSElasticBeanstalkClient | ||
import com.amazonaws.services.elasticbeanstalk.model.{ApplicationVersionDescription, S3Location} | ||
import sbt.{SettingKey, TaskKey} | ||
|
||
object EbKeys { | ||
//TODO: Investigate adding an `isSnapshot` key and overwriting existing snapshots if it is to allow repeated uploads. Would require a delete app version task | ||
|
||
//User set | ||
val ebS3BucketName = SettingKey[String]("ebS3BucketName", "S3 bucket which should contain uploaded zip files") | ||
|
||
//User set. If possible default to `stage in Docker` | ||
//TODO: Support multiple files. That way you get the source as well as the .ebextensions. Or have that as an optional other setting | ||
val ebAppBundleSource = TaskKey[File]("eb-app-bundle-source", "Source to be zipped to a deployable app bundle") | ||
|
||
//User set | ||
val ebRegion = SettingKey[String]("ebRegion", "Elastic Beanstalk region (e.g., us-west-1)") | ||
|
||
val ebAppBundle = TaskKey[File]("eb-app-bundle", "The application file ('source bundle' in AWS terms) to deploy.") | ||
|
||
val ebCreateVersion = TaskKey[ApplicationVersionDescription]("eb-create-version", "Creates a new application version in the configured environment.") | ||
|
||
val ebUploadSourceBundle = TaskKey[S3Location]("eb-upload-source-bundle", "Uploads the WAR source bundle to S3") | ||
|
||
val ebClient = TaskKey[AWSElasticBeanstalkClient]("eb-client") | ||
|
||
val ebStageTarget = SettingKey[File]("ebStageTarget", "location of eb staging target") | ||
|
||
val ebVersion = TaskKey[String]("ebVersion", "version label and appBundle name to be used ") | ||
|
||
val ebAppName = SettingKey[String]("ebAppName", "Name of the application on elastic beanstalk") | ||
|
||
val ebDescription = TaskKey[String]("eb-description", "description of created version") | ||
} | ||
|
||
//TODO: AutoPlugin that if native packager is enabled sets the bundleSource. And if git-sbt is enabled, sets the version and description | ||
trait EbSettings { this: EbTasks => | ||
import EbKeys._ | ||
import sbt.Keys.{name, target, version} | ||
import sbt._ | ||
|
||
lazy val ebSettings = Seq[Setting[_]]( | ||
ebCreateVersion <<= ebCreateVersionTask, | ||
ebUploadSourceBundle <<= ebUploadSourceBundleTask, | ||
ebAppBundle <<= ebAppBundleTask, | ||
ebClient <<= ebRegion map { (region) => ApplicationDeployer.getEBClient(region) }, | ||
ebVersion := version.value, | ||
ebStageTarget := (target.value / "eb"), | ||
ebRegion := "eu-west-1", | ||
ebAppName := name.value | ||
) | ||
} | ||
|
||
trait EbTasks { | ||
import sbt.IO | ||
import sbt.Keys.streams | ||
|
||
val ebAppBundleTask = (EbKeys.ebStageTarget, EbKeys.ebAppBundleSource, EbKeys.ebVersion, streams) map { | ||
(staging, docTar, versionLabel, s) => | ||
val zipFile = new File(staging, s"$versionLabel.zip") | ||
s.log.info(s"Cleaning elastic-beanstalk staging directory $staging") | ||
|
||
IO.delete(staging) | ||
|
||
s.log.info(s"Writing elastic-beanstalk app bundle to $zipFile") | ||
|
||
def entries(f: File):List[File] = f :: (if (f.isDirectory) IO.listFiles(f).toList.flatMap(entries) else Nil) | ||
IO.zip(entries(docTar).collect{case d if d.getAbsolutePath != docTar.getAbsolutePath => (d, d.getAbsolutePath.substring(docTar.getAbsolutePath.length +1))}, zipFile) | ||
zipFile | ||
} | ||
|
||
val ebUploadSourceBundleTask = (EbKeys.ebAppBundle, EbKeys.ebS3BucketName, EbKeys.ebAppName, streams) map { | ||
(appBundle, s3BucketName, appName, s) => { | ||
require(appBundle.getName.endsWith("zip"), "App bundle must be a zip archive") | ||
|
||
s.log.info("Uploading " + appBundle.getName + " (" + (appBundle.length/1024/1024) + " MB) " + | ||
"to Amazon S3 bucket '" + s3BucketName + "'") | ||
BundleUploader.uploadBundle(s3BucketName, appBundle, s"$appName/${appBundle.getName}") | ||
} | ||
} | ||
|
||
val ebCreateVersionTask = (EbKeys.ebClient, EbKeys.ebUploadSourceBundle, EbKeys.ebAppName, EbKeys.ebVersion, EbKeys.ebDescription, streams) map { | ||
(ebClient, ebSourceBundle, appName, versionLabel, description, s) => | ||
|
||
s.log.info(s"Creating application: $appName version: $versionLabel description: $description from s3: $ebSourceBundle") | ||
ApplicationDeployer.createEbVersion(ebClient, appName, versionLabel, description, ebSourceBundle). | ||
getApplicationVersion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
|
||
import sbt.Plugin | ||
|
||
//TODO: Make AutoPlugin | ||
object EB extends Plugin with EbSettings with EbTasks |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import com.typesafe.sbt.packager.docker._ | ||
import EbKeys._ | ||
import EB._ | ||
|
||
|
||
name := "test-app" | ||
version := "2.1" | ||
scalaVersion := "2.11.7" | ||
|
||
scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8") | ||
|
||
libraryDependencies ++= { | ||
val akkaStreamV = "1.0" | ||
Seq( | ||
"com.typesafe.akka" %% "akka-http-experimental" % akkaStreamV | ||
) | ||
} | ||
|
||
enablePlugins(JavaAppPackaging) | ||
|
||
sourceDirectory in Docker := baseDirectory.value / "docker" | ||
|
||
dockerBaseImage := "java:8" | ||
|
||
maintainer in Docker := "frosforever" | ||
|
||
dockerExposedPorts := Seq(9000) | ||
|
||
//Manually building dockerFile to have better control and to ensure chmod is called before running | ||
dockerCommands := Seq( | ||
Cmd("FROM", dockerBaseImage.value), | ||
Cmd("MAINTAINER", (maintainer in Docker).value), | ||
Cmd("EXPOSE", dockerExposedPorts.value.mkString(" ")), | ||
Cmd("ADD", { | ||
val files = (defaultLinuxInstallLocation in Docker).value.split(java.io.File.separator)(1) | ||
s"$files /$files" | ||
}), | ||
Cmd("WORKDIR", s"${(defaultLinuxInstallLocation in Docker).value}"), | ||
ExecCmd("RUN", "chown", "-R", (daemonUser in Docker).value, "."), | ||
ExecCmd("RUN", "chmod", "+x", | ||
s"${(defaultLinuxInstallLocation in Docker).value}/bin/${executableScriptName.value}"), | ||
Cmd("USER", (daemonUser in Docker).value), | ||
ExecCmd("ENTRYPOINT", s"bin/${name.value}"), | ||
ExecCmd("CMD") | ||
) | ||
|
||
ebSettings | ||
|
||
ebS3BucketName := "us-west-1-test-bucket" | ||
|
||
ebAppBundleSource := (stage in Docker).value | ||
|
||
ebRegion := "us-west-1" | ||
|
||
ebDescription := "hello" | ||
|
||
ebAppName := "My First Elastic Beanstalk Application" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
files: | ||
"/etc/nginx/conf.d/proxy.conf" : | ||
mode: "000755" | ||
owner: root | ||
group: root | ||
content: | | ||
client_max_body_size 80m; | ||
proxy_connect_timeout 600; | ||
proxy_send_timeout 600; | ||
proxy_read_timeout 600; | ||
send_timeout 600; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"AWSEBDockerrunVersion": "1", | ||
"Ports": [ | ||
{ | ||
"ContainerPort": "9000" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
sbt.version=0.13.8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
//addSbtPlugin("io.spray" % "sbt-revolver" % "0.7.2") | ||
|
||
//addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0") | ||
|
||
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.0.1") | ||
|
||
lazy val root = Project("plugins", file(".")).dependsOn(plugin) | ||
|
||
lazy val plugin = file("../").getCanonicalFile.toURI |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import akka.actor.ActorSystem | ||
import akka.http.scaladsl.Http | ||
import akka.http.scaladsl.server.Directives._ | ||
import akka.stream.{ActorMaterializer, Materializer} | ||
import scala.concurrent.ExecutionContextExecutor | ||
|
||
object HelloWorld extends App with Service { | ||
override implicit val system = ActorSystem() | ||
override implicit val executor = system.dispatcher | ||
override implicit val materializer = ActorMaterializer() | ||
|
||
Http().bindAndHandle(routes, "0.0.0.0", 9000) | ||
} | ||
|
||
trait Service { | ||
implicit val system: ActorSystem | ||
implicit def executor: ExecutionContextExecutor | ||
implicit val materializer: Materializer | ||
|
||
val routes = get { | ||
complete { | ||
"hello world from version 2.1!" | ||
} | ||
} | ||
} |