We are using Gitlab.com as our central GIT repo. In the same way, to deploy the app to AWS Elastic Beanstalk it is pushed using git aws.push, it in the background do a normal git push to Amazon. I want a way to push to gitlab and Gitlab do the push to Elastic Beanstalk. I know about git alias, using it I'm able to execute git push and git aws.push using one command, but, what I want is push only to gitlab and from gitlab to AWS.
I'm thinking in Gitlab Web Hooks, maybe some already translate it to PHP or some server language to implement the Web Hook? or any other solution to deploy from Gitlab to AWS Elastic Beanstalk.
There is the code in Power Shell used by git aws.push to do a git push to Elastic Beanstalk:
$awsSource = @"
using System;
using System.Globalization;
using System.Text;
using System.Security.Cryptography;
namespace Amazon.DevTools
{
public class AWSUser
{
public string AccessKey
{
get;
set;
}
public string SecretKey
{
get;
set;
}
protected internal void Validate()
{
if (string.IsNullOrEmpty(this.AccessKey))
{
throw new InvalidOperationException("[AccessKey]");
}
if (string.IsNullOrEmpty(this.SecretKey))
{
throw new InvalidOperationException("[SecretKey]");
}
}
}
}
namespace Amazon.DevTools
{
public abstract class AWSDevToolsRequest
{
protected const string METHOD = "GIT";
protected const string SERVICE = "devtools";
DateTime dateTime;
public AWSDevToolsRequest()
: this(DateTime.UtcNow)
{
}
public AWSDevToolsRequest(DateTime dateTime)
{
if (dateTime == null)
{
throw new ArgumentNullException("dateTime");
}
this.dateTime = dateTime.ToUniversalTime();
}
public string DateStamp
{
get
{
return this.dateTime.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
}
}
public string DateTimeStamp
{
get
{
return this.dateTime.ToString("yyyyMMddTHHmmss", CultureInfo.InvariantCulture);
}
}
public abstract string DerivePath();
protected internal abstract string DeriveRequest();
public string Host
{
get;
set;
}
public string Region
{
get;
set;
}
public string Service
{
get
{
return AWSDevToolsRequest.SERVICE;
}
}
protected internal virtual void Validate()
{
if (string.IsNullOrEmpty(this.Host))
{
throw new InvalidOperationException("[Host]");
}
if (string.IsNullOrEmpty(this.Region))
{
throw new InvalidOperationException("[Region]");
}
}
}
}
namespace Amazon.DevTools
{
public class AWSElasticBeanstalkRequest : AWSDevToolsRequest
{
public AWSElasticBeanstalkRequest()
: base()
{
}
public AWSElasticBeanstalkRequest(DateTime dateTime)
: base(dateTime)
{
}
public string Application
{
get;
set;
}
public override string DerivePath()
{
this.Validate();
string path = null;
if (string.IsNullOrEmpty(this.Environment))
{
path = string.Format("/v1/repos/{0}/commitid/{1}"
, this.Encode(this.Application)
, this.Encode(this.CommitId));
}
else
{
path = string.Format("/v1/repos/{0}/commitid/{1}/environment/{2}"
, this.Encode(this.Application)
, this.Encode(this.CommitId)
, this.Encode(this.Environment));
}
return path;
}
protected internal override string DeriveRequest()
{
this.Validate();
string path = this.DerivePath();
string request = string.Format("{0}\n{1}\n\nhost:{2}\n\nhost\n", AWSDevToolsRequest.METHOD, path, this.Host);
return request;
}
public string Environment
{
get;
set;
}
public string CommitId
{
get;
set;
}
protected internal override void Validate()
{
base.Validate();
if (string.IsNullOrEmpty(this.Application))
{
throw new InvalidOperationException("[Application]");
}
if (string.IsNullOrEmpty(this.Host))
{
throw new InvalidOperationException("[Host]");
}
}
protected internal string Encode(string plaintext)
{
StringBuilder sb = new StringBuilder();
foreach (byte b in new UTF8Encoding().GetBytes(plaintext))
{
sb.Append(b.ToString("x2", CultureInfo.InvariantCulture));
}
return sb.ToString();
}
}
}
namespace Amazon.DevTools
{
public class AWSDevToolsAuth
{
const string AWS_ALGORITHM = "HMAC-SHA256";
const string HASH_ALGORITHM = "SHA-256";
const string HMAC_ALGORITHM = "HMACSHA256";
const string SCHEME = "AWS4";
const string TERMINATOR = "aws4_request";
AWSUser user;
AWSDevToolsRequest request;
public AWSDevToolsAuth(AWSUser user, AWSDevToolsRequest request)
{
this.user = user;
this.request = request;
}
static byte[] DeriveKey(AWSUser user, AWSDevToolsRequest request)
{
string secret = string.Format("{0}{1}", AWSDevToolsAuth.SCHEME, user.SecretKey);
byte[] kSecret = Encoding.UTF8.GetBytes(secret);
byte[] kDate = AWSDevToolsAuth.Hash(AWSDevToolsAuth.HMAC_ALGORITHM, kSecret, Encoding.UTF8.GetBytes(request.DateStamp));
byte[] kRegion = AWSDevToolsAuth.Hash(AWSDevToolsAuth.HMAC_ALGORITHM, kDate, Encoding.UTF8.GetBytes(request.Region));
byte[] kService = AWSDevToolsAuth.Hash(AWSDevToolsAuth.HMAC_ALGORITHM, kRegion, Encoding.UTF8.GetBytes(request.Service));
byte[] key = AWSDevToolsAuth.Hash(AWSDevToolsAuth.HMAC_ALGORITHM, kService, Encoding.UTF8.GetBytes(AWSDevToolsAuth.TERMINATOR));
return key;
}
public string DerivePassword()
{
this.user.Validate();
this.request.Validate();
string signature = AWSDevToolsAuth.SignRequest(this.user, this.request);
string password = string.Format("{0}Z{1}", this.request.DateTimeStamp, signature);
return password;
}
public Uri DeriveRemote()
{
this.request.Validate();
string path = this.request.DerivePath();
string password = this.DerivePassword();
string username = this.DeriveUserName();
UriBuilder remote = new UriBuilder()
{
Host = this.request.Host,
Path = path,
Password = password,
Scheme = "https",
UserName = username,
};
return remote.Uri;
}
public string DeriveUserName()
{
this.user.Validate();
return this.user.AccessKey;
}
static byte[] Hash(string algorithm, byte[] message)
{
HashAlgorithm hash = HashAlgorithm.Create(algorithm);
byte[] digest = hash.ComputeHash(message);
return digest;
}
static byte[] Hash(string algorithm, byte[] key, byte[] message)
{
KeyedHashAlgorithm hash = KeyedHashAlgorithm.Create(algorithm);
hash.Key = key;
byte[] digest = hash.ComputeHash(message);
return digest;
}
static string SignRequest(AWSUser user, AWSDevToolsRequest request)
{
string scope = string.Format("{0}/{1}/{2}/{3}", request.DateStamp, request.Region, request.Service, AWSDevToolsAuth.TERMINATOR);
StringBuilder stringToSign = new StringBuilder();
stringToSign.AppendFormat("{0}-{1}\n{2}\n{3}\n", AWSDevToolsAuth.SCHEME, AWSDevToolsAuth.AWS_ALGORITHM, request.DateTimeStamp, scope);
byte[] requestBytes = Encoding.UTF8.GetBytes(request.DeriveRequest());
byte[] requestDigest = AWSDevToolsAuth.Hash(AWSDevToolsAuth.HASH_ALGORITHM, requestBytes);
stringToSign.Append(AWSDevToolsAuth.ToHex(requestDigest));
byte[] key = AWSDevToolsAuth.DeriveKey(user, request);
byte[] digest = AWSDevToolsAuth.Hash(AWSDevToolsAuth.HMAC_ALGORITHM, key, Encoding.UTF8.GetBytes(stringToSign.ToString()));
string signature = AWSDevToolsAuth.ToHex(digest);
return signature;
}
static string ToHex(byte[] data)
{
StringBuilder hex = new StringBuilder();
foreach (byte b in data)
{
hex.Append(b.ToString("x2", CultureInfo.InvariantCulture));
}
return hex.ToString();
}
}
}
"@
Add-Type -Language CSharpVersion3 -TypeDefinition $awsSource
# -*-powershell-*-
#
# Sets the AWS.push configuration values
#
# Will read values from the pipeline input if none are present the values are read from the console input instead.
#
function Edit-AWSElasticBeanstalkRemote
{
$data=@($input)
$used=0
$config = Read-Config $False $True
$awsAccessKey = Lookup-Setting $config "global" "AWSAccessKeyId" ("cred","git")
if (!$awsAccessKey -and (ShouldWrite-Credentials $config $false))
{
$awsAccessKeyInput = ($data[$used++] | Input-Data "AWS Access Key")
}
if ($awsAccessKeyInput)
{
$config = Write-Setting $config "cred" "global" "AWSAccessKeyId" $awsAccessKeyInput
}
$awsSecretKey = Lookup-Setting $config "global" "AWSSecretKey" ("cred","git")
if (!$awsSecretKey -and (ShouldWrite-Credentials $config $false))
{
$awsSecretKeyInput = ($data[$used++] | Input-Data "AWS Secret Key")
}
if ($awsSecretKeyInput)
{
$config = Write-Setting $config "cred" "global" "AWSSecretKey" $awsSecretKeyInput
}
$awsRegion = Lookup-Setting $config "global" "Region" ("eb","git")
if (-not $awsRegion)
{
$awsRegion = "us-east-1"
$config = Write-Setting $config "eb" "global" "Region" $awsRegion
}
$awsRegionInput = ($data[$used++] | Input-Data "AWS Region [default to $($awsRegion)]")
if ($awsRegionInput)
{
$awsRegion = $awsRegionInput
$config = Write-Setting $config "eb" "global" "Region" $awsRegionInput
}
$awsHost = Get-Endpoint $awsRegion
if ($awsHost)
{
$config = Write-Setting $config "eb" "global" "DevToolsEndpoint" $awsHost
}
else
{
$awsHostInput = ($data[$used++] | Input-Data "AWS Host [default to git.elasticbeanstalk.us-east-1.amazonaws.com]")
if ($awsHostInput)
{
$config = Write-Setting $config "eb" "global" "DevToolsEndpoint" $awsHostInput
}
else
{
$config = Write-Setting $config "eb" "global" "DevToolsEndpoint" "git.elasticbeanstalk.us-east-1.amazonaws.com"
}
}
$awsApplication = Lookup-Setting $config "global" "ApplicationName" ("eb","git")
if ($awsApplication)
{
$awsApplicationInput = ($data[$used++] | Input-Data "AWS Elastic Beanstalk Application [default to $($awsApplication)]")
}
else
{
$awsApplicationInput = ($data[$used++] | Input-Data "AWS Elastic Beanstalk Application")
}
if ($awsApplicationInput)
{
$config = Write-Setting $config "eb" "global" "ApplicationName" $awsApplicationInput
}
$awsEnvironment = Lookup-Setting $config "global" "EnvironmentName" ("eb","git")
if ($awsEnvironment)
{
$awsEnvironmentInput = ($data[$used++] | Input-Data "AWS Elastic Beanstalk Environment [default to $($awsEnvironment)]")
}
else
{
$awsEnvironmentInput = ($data[$used++] | Input-Data "AWS Elastic Beanstalk Environment")
}
if ($awsEnvironmentInput)
{
$config = Write-Setting $config "eb" "global" "EnvironmentName" $awsEnvironmentInput
}
Write-Config $config
}
#
# Looks up the endpoint for a region
#
# @params $region
# @return The endpoint
#
function Get-Endpoint
{
Param($region)
switch ($region)
{
"us-east-1" { $endpoint = "git.elasticbeanstalk.us-east-1.amazonaws.com" }
"ap-northeast-1" { $endpoint = "git.elasticbeanstalk.ap-northeast-1.amazonaws.com" }
"ap-southeast-1" { $endpoint = "git.elasticbeanstalk.ap-southeast-1.amazonaws.com" }
"ap-southeast-2" { $endpoint = "git.elasticbeanstalk.ap-southeast-2.amazonaws.com" }
"eu-west-1" { $endpoint = "git.elasticbeanstalk.eu-west-1.amazonaws.com" }
"sa-east-1" { $endpoint = "git.elasticbeanstalk.sa-east-1.amazonaws.com" }
"us-west-1" { $endpoint = "git.elasticbeanstalk.us-west-1.amazonaws.com" }
"us-west-2" { $endpoint = "git.elasticbeanstalk.us-west-2.amazonaws.com" }
}
$endpoint
}
#
# Gets the remote URL used for AWS.push
#
# @param $e environment that is deployed too.
# @param $c commit to deploy
# @return The URL
#
function Get-AWSElasticBeanstalkRemote
{
Param([string] $e,
[string] $c,
[bool] $toPush = $FALSE )
trap [System.Management.Automation.MethodInvocationException]
{
if ($_.Exception -and $_.Exception.InnerException)
{
$awsOption = $_.Exception.InnerException.Message
switch ($awsOption)
{
"[AccessKey]" { $awsOption = "aws.accesskey" }
"[Application]" { $awsOption = "aws.elasticbeanstalk.application" }
"[Host]" { $awsOption = "aws.elasticbeanstalk.host" }
"[Region]" { $awsOption = "aws.region" }
"[SecretKey]" { $awsOption = "aws.secretkey" }
}
Write-Host "Missing configuration setting for: $($awsOption)"
}
else
{
Write-Host "An unknown error occurred while computing your temporary password."
}
Write-Host "`nTry running 'git aws.config' to update your repository configuration."
Exit
}
$config = Read-Config
$awsAccessKey = Lookup-Setting $config "global" "AWSAccessKeyId" ("cred","git")
$awsSecretKey = Lookup-Setting $config "global" "AWSSecretKey" ("cred","git")
$awsRegion = Lookup-Setting $config "global" "Region" ("eb","git")
$awsHost = Lookup-Setting $config "global" "DevToolsEndpoint" ("eb","git")
$awsApplication = Lookup-Setting $config "global" "ApplicationName" ("eb","git")
if ($e)
{
$awsEnvironment = $e
}
else
{
$branchName = &git rev-parse --abbrev-ref HEAD
$defaultEnv = Lookup-Setting $config "branches" $branchName ("eb")
if ($defaultEnv)
{
$awsEnvironment = $defaultEnv
}
else
{
$awsEnvironment = Lookup-Setting $config "global" "EnvironmentName" ("eb","git")
}
}
$gitCommitId = $c
$awsUser = New-Object -TypeName Amazon.DevTools.AWSUser
$awsUser.AccessKey = $awsAccessKey
$awsUser.SecretKey = $awsSecretKey
$awsRequest = New-Object -TypeName Amazon.DevTools.AWSElasticBeanstalkRequest
$awsRequest.Region = $awsRegion
$awsRequest.Host = $awsHost
$awsRequest.Application = $awsApplication
$awsRequest.Environment = $awsEnvironment
$awsRequest.CommitId = $gitCommitId
$awsAuth = New-Object -TypeName Amazon.DevTools.AWSDevToolsAuth $awsUser,$awsRequest
$awsRemote = $awsAuth.DeriveRemote()
if($toPush) {
Write-Host "Pushing to environment: $awsEnvironment"
}
return $awsRemote.ToString()
}
#
# Performs the aws.push
#
# @param $e environment that is deployed too.
# @param $c commit to deploy
#
function Invoke-AWSElasticBeanstalkPush
{
Param([string] $e, [string] $c)
$remote = Get-AWSElasticBeanstalkRemote $e $c $TRUE
$src = $c
$dst = "refs/heads/master"
$commit = $src + ":" + $dst
&git push -f $remote $commit
}
#
# Adds the git aliases for aws.push and aws.config to the git repository.
#
function Initialize-AWSElasticBeanstalkRepository
{
$command = 'Import-Module AWSDevTools; $e, $c = Get-Options $args; Get-AWSElasticBeanstalkRemote $e $c'
&git config alias.aws.elasticbeanstalk.remote "!powershell -noprofile -executionpolicy bypass -command '& { $command }'"
$command = 'Import-Module AWSDevTools; $e, $c = Get-Options $args; Invoke-AWSElasticBeanstalkPush $e $c'
&git config alias.aws.push "!powershell -noprofile -executionpolicy bypass -command '& { $command }'"
$command = 'Import-Module AWSDevTools; Edit-AWSElasticBeanstalkRemote'
&git config alias.aws.config "!powershell -noprofile -executionpolicy bypass -command '& { $command }'"
}
#
# Read in data
#
# Will used pipeline data if present, otherwise reads from the console
#
# @param $message The text to display as a prompt
# @return The data collected
#
function Input-Data
{
Param([string] $message)
Write-Host -NoNewline "$($message): "
if (($input.MoveNext()) -and ($input.Current))
{
Write-Host $input.Current
$input.Current
}
else
{
[Console]::In.ReadLine()
}
}
#
# Gets the values for the aws.push and aws.config command options
#
# @param $arr The command line options passed to the command
# @return The options values
#
function Get-Options
{
Param([string[]] $arr)
$e = $null;
$c = $null;
$optionmappings = @{
'--environment' = 'environment';
'-e' = 'environment';
'--commit' = 'commit';
'-c' = 'commit';
'--help' = 'help';
'-h' = 'help'
}
$options = @{}
for ($i=0; $i -lt $arr.count; $i++)
{
$optname = $arr[$i]
$mappedoption = $optionmappings[$optname]
if (!$mappedoption) {
Write-Host("Unknown Option: {0}" -f $arr[$i])
Write-Help
Exit
}
if ($mappedoption -eq "help") {
Write-Help
Exit
}
$value = $arr[++$i]
if (($value -eq $null) -or $optionmappings[$value]) {
Write-Host("You must provide a value for {0}" -f $optname)
Write-Help
Exit
}
if ($options[$mappedoption]) {
Write-Host("--{0} specified twice" -f $mappedoption)
Exit
}
$options[$mappedoption] = $value
}
$e = $options["environment"]
$c = $options["commit"]
if ($c -eq $null) {
$c = "HEAD"
}
$c = Parse-CommitOption $c
$result = $e, $c
$result
}
Right-click the instance ID for the Amazon EC2 instance running in your environment's load balancer, and then select Connect from the context menu. Make a note of the instance's public DNS address on the Description tab. Connect to an instance running Linux by using the SSH client of your choice, and then type ssh -i .
First set your AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
in gitlab: https://gitlab.com/snw/<project_name>/settings/ci_cd
Then add a .gitlab-ci.yml
file to your repo's root:
variables:
ARCHIVE_NAME: "archive.zip"
ARCHIVE_LOCATION: "deployments/"
S3_BUCKET_NAME: "my-deployments"
ELASTIC_BEANSTALK_APP_NAME: "myAppName"
AWS_REGION: "us-east-1"
elastic_beanstalk_deploy:
image: python:latest
script:
- apt-get update --assume-yes
- apt-get install zip --assume-yes
- zip -r $ARCHIVE_LOCATION$ARCHIVE_NAME .
- pip install awscli
- aws s3 cp $ARCHIVE_LOCATION$ARCHIVE_NAME s3://$S3_BUCKET_NAME/
- aws elasticbeanstalk create-application-version --application-name $ELASTIC_BEANSTALK_APP_NAME --version-label `date "+%Y%m%d-%H%M%S"` --description "$(git log -1 --pretty=%B)" --source-bundle S3Bucket="$S3_BUCKET_NAME",S3Key="$ARCHIVE_NAME" --region $AWS_REGION
Props to:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With