Allow reuse of the EBS volume or create a new one based on a snapshot
Currently every single-master stack creates new EBS volume. Reusing the
volume allows to preserve the data.
Feature: Issue 13407
Change-Id: I8c2c831e73ef110c945838093c3f55abad013696
diff --git a/Makefile.common b/Makefile.common
index 35ff78a..efcc0c3 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -17,6 +17,7 @@
aws s3api create-bucket $(CREATE_BUCKET_PARAMS)
aws s3 cp ../common-templates/cf-gerrit-task-execution-role.yml s3://$(TEMPLATE_BUCKET_NAME)/
aws s3 cp ../common-templates/cf-gerrit-network-stack.yml s3://$(TEMPLATE_BUCKET_NAME)/
+ aws s3 cp ../common-templates/cf-gerrit-volume.yml s3://$(TEMPLATE_BUCKET_NAME)/
set-optional-params-metrics-cloudwatch:
ifdef METRICS_CLOUDWATCH_ENABLED
diff --git a/common-templates/cf-gerrit-volume.yml b/common-templates/cf-gerrit-volume.yml
new file mode 100644
index 0000000..05c9b43
--- /dev/null
+++ b/common-templates/cf-gerrit-volume.yml
@@ -0,0 +1,36 @@
+AWSTemplateFormatVersion: '2010-09-09'
+Description: Deploy an EBS Volume for Gerrit service data.
+Parameters:
+ GerritVolumeId:
+ Description: Existing Gerrit volume id
+ Type: String
+ Default: ""
+ GerritVolumeSnapshotId:
+ Description: Id of the EBS snapshot for Gerrit volume
+ Type: String
+ Default: ""
+ GerritVolumeSizeInGiB:
+ Description: Gerrit volume size in GiB
+ Type: Number
+ Default: 10
+
+Conditions:
+ CreateEBSVolume: !Equals [!Ref GerritVolumeId, ""]
+ CreateEBSVolumeBasedOnSnapshot: !Not
+ - !Equals [!Ref GerritVolumeSnapshotId, ""]
+
+Resources:
+ GerritVolume:
+ Condition: CreateEBSVolume
+ Type: AWS::EC2::Volume
+ Properties:
+ AvailabilityZone: !Select
+ - 0
+ - !GetAZs
+ Ref: 'AWS::Region'
+ SnapshotId: !If [CreateEBSVolumeBasedOnSnapshot, !Ref GerritVolumeSnapshotId, !Ref "AWS::NoValue"]
+ Size: !If [CreateEBSVolumeBasedOnSnapshot, !Ref "AWS::NoValue", !Ref GerritVolumeSizeInGiB]
+
+Outputs:
+ GerritVolumeRef:
+ Value: !If [CreateEBSVolume, !Ref "GerritVolume", !Ref "GerritVolumeId"]
\ No newline at end of file
diff --git a/single-master/Makefile b/single-master/Makefile
index eb3ca8e..13d0205 100644
--- a/single-master/Makefile
+++ b/single-master/Makefile
@@ -29,6 +29,15 @@
ifdef VPC_CIDR
$(eval CLUSTER_OPTIONAL_PARAMS := $(CLUSTER_OPTIONAL_PARAMS) ParameterKey=VPCCIDR,ParameterValue=$(VPC_CIDR))
endif
+ifdef GERRIT_VOLUME_ID
+ $(eval CLUSTER_OPTIONAL_PARAMS := $(CLUSTER_OPTIONAL_PARAMS) ParameterKey=GerritVolumeId,ParameterValue=$(GERRIT_VOLUME_ID))
+endif
+ifdef GERRIT_VOLUME_SNAPSHOT_ID
+ $(eval CLUSTER_OPTIONAL_PARAMS := $(CLUSTER_OPTIONAL_PARAMS) ParameterKey=GerritVolumeSnapshotId,ParameterValue=$(GERRIT_VOLUME_SNAPSHOT_ID))
+endif
+ifdef GERRIT_VOLUME_SIZE_IN_GIB
+ $(eval CLUSTER_OPTIONAL_PARAMS := $(CLUSTER_OPTIONAL_PARAMS) ParameterKey=GerritVolumeSizeInGiB,ParameterValue=$(GERRIT_VOLUME_SIZE_IN_GIB))
+endif
$(AWS_FC_COMMAND) create-stack \
--stack-name $(CLUSTER_STACK_NAME) \
diff --git a/single-master/README.md b/single-master/README.md
index c098806..d47f899 100644
--- a/single-master/README.md
+++ b/single-master/README.md
@@ -73,6 +73,11 @@
* `SERVICE_STACK_NAME`: Optional. Name of the service stack. `gerrit-service` by default.
* `GERRIT_INSTANCE_ID`: Optional. Identifier for the Gerrit instance. "gerrit-single-master" by default.
+* `GERRIT_VOLUME_ID` : Optional. Id of an extisting EBS volume. If empty, a new volume
+for Gerrit data will be created
+* `GERRIT_VOLUME_SNAPSHOT_ID` : Optional. Ignored if GERRIT_VOLUME_ID is not empty. Id of
+the EBS volume snapshot used to create new EBS volume for Gerrit data.
+* `GERRIT_VOLUME_SIZE_IN_GIB`: Optional. The size of the Gerrit data volume, in GiBs. `10` by default.
### 2 - Deploy
diff --git a/single-master/cf-cluster.yml b/single-master/cf-cluster.yml
index 41327df..356b252 100644
--- a/single-master/cf-cluster.yml
+++ b/single-master/cf-cluster.yml
@@ -56,6 +56,27 @@
Description: An environment name that will be prefixed to resource names
Type: String
Default: test
+ GerritVolumeId:
+ Description: Existing Gerrit volume id
+ Type: String
+ Default: ""
+ GerritVolumeSnapshotId:
+ Description: Id of the EBS snapshot for Gerrit volume
+ Type: String
+ Default: ""
+ GerritVolumeAttachMaxRetries:
+ Description: Maximum number of retries when attaching Gerrit Volume
+ Type: Number
+ Default: 5
+ GerritVolumeAttachRetryDelay:
+ Description: The delay in seconds between Gerrit Volume attach attempts
+ Type: Number
+ Default: 5
+ GerritVolumeSizeInGiB:
+ Description: Gerrit volume size in GiB
+ Type: Number
+ Default: 10
+
Resources:
# ECS Resources
ECSCluster:
@@ -108,7 +129,46 @@
echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config
# Make sure latest version of the helper scripts are installed as per recommendation:
# https://github.com/awsdocs/aws-cloudformation-user-guide/blob/master/doc_source/cfn-helper-scripts-reference.md#using-the-latest-version
- yum install -y aws-cfn-bootstrap
+ yum install -y aws-cfn-bootstrap aws-cli xfsprogs
+ EC2_INSTANCE_ID=`curl -s http://169.254.169.254/latest/meta-data/instance-id`
+ VOLUME_ID=${GerritVolumeStack.Outputs.GerritVolumeRef}
+ echo "Volume Id: $VOLUME_ID"
+
+ aws ec2 attach-volume --region ${AWS::Region} --volume-id $VOLUME_ID --instance-id $EC2_INSTANCE_ID --device /dev/xvdg
+
+ for i in $(seq 1 ${GerritVolumeAttachMaxRetries}); do
+ echo "Waiting for volume $VOLUME_ID to be attached to the instace $EC2_INSTANCE_ID"
+ volumeStatus=`aws ec2 describe-volumes --region ${AWS::Region} --volume-ids $VOLUME_ID`
+ if [[ $volumeStatus =~ "\"State\": \"attached\"" ]]; then
+ echo "Volume $VOLUME_ID attached to the instace $EC2_INSTANCE_ID"
+ break
+ elif [[ "$i" -eq "${GerritVolumeAttachMaxRetries}" ]]; then
+ echo "Could not attach the volume $VOLUME_ID to the instace $EC2_INSTANCE_ID"
+ exit 1
+ fi
+ sleep ${GerritVolumeAttachRetryDelay}
+ done
+
+ if [[ "${GerritVolumeId}" = "" && "${GerritVolumeSnapshotId}" = "" ]]; then
+ echo "Create file system for Gerrit volume"
+ mkfs -t xfs /dev/xvdg
+ fi
+
+ mkdir /gerrit-mount-point
+ mount /dev/xvdg /gerrit-mount-point
+
+ if [[ "${GerritVolumeId}" = "" && "${GerritVolumeSnapshotId}" = "" ]]; then
+ echo "Create Gerrit directories"
+ mkdir -p /gerrit-mount-point/gerrit-logs \
+ /gerrit-mount-point/gerrit-cache \
+ /gerrit-mount-point/gerrit-data \
+ /gerrit-mount-point/gerrit-git \
+ /gerrit-mount-point/gerrit-index \
+ /gerrit-mount-point/gerrit-db
+ fi
+
+ chown 1000:1000 -R /gerrit-mount-point
+
# Get the CloudWatch Logs agent
echo -e "
{\"logs\":
@@ -116,22 +176,22 @@
{\"files\":
{\"collect_list\":
[
- {\"file_path\": \"/var/lib/docker/volumes/gerrit-logs/_data/httpd_log\",
+ {\"file_path\": \"/gerrit-mount-point/gerrit-logs/httpd_log\",
\"log_group_name\": \"${AWS::StackName}\",
\"log_stream_name\": \"${EnvironmentName}/{instance_id}/httpd_log\",
\"timezone\": \"UTC\"
},
- {\"file_path\": \"/var/lib/docker/volumes/gerrit-logs/_data/sshd_log\",
+ {\"file_path\": \"/gerrit-mount-point/gerrit-logs/sshd_log\",
\"log_group_name\": \"${AWS::StackName}\",
\"log_stream_name\": \"${EnvironmentName}/{instance_id}/sshd_log\",
\"timezone\": \"UTC\"
},
- {\"file_path\": \"/var/lib/docker/volumes/gerrit-logs/_data/gc_log\",
+ {\"file_path\": \"/gerrit-mount-point/gerrit-logs/gc_log\",
\"log_group_name\": \"${AWS::StackName}\",
\"log_stream_name\": \"${EnvironmentName}/{instance_id}/gc_log\",
\"timezone\": \"UTC\"
},
- {\"file_path\": \"/var/lib/docker/volumes/gerrit-logs/_data/audit_log\",
+ {\"file_path\": \"/gerrit-mount-point/gerrit-logs/audit_log\",
\"log_group_name\": \"${AWS::StackName}\",
\"log_stream_name\": \"${EnvironmentName}/{instance_id}/audit_log\",
\"timezone\": \"UTC\"
@@ -186,6 +246,8 @@
- 'ecr:GetAuthorizationToken'
- 'ecr:BatchGetImage'
- 'ecr:GetDownloadUrlForLayer'
+ - 'ec2:AttachVolume'
+ - 'ec2:DescribeVolumes'
Resource: '*'
ECSTaskNetworkStack:
@@ -200,6 +262,16 @@
SubnetIdProp: !Ref 'SubnetIdProp'
SubnetCIDR: !Ref 'SubnetCIDR'
+ GerritVolumeStack:
+ Type: AWS::CloudFormation::Stack
+ Properties:
+ TemplateURL: !Join [ '', ['https://', !Ref TemplateBucketName, '.s3.amazonaws.com/cf-gerrit-volume.yml'] ]
+ TimeoutInMinutes: '25'
+ Parameters:
+ GerritVolumeId: !Ref 'GerritVolumeId'
+ GerritVolumeSnapshotId: !Ref 'GerritVolumeSnapshotId'
+ GerritVolumeSizeInGiB: !Ref 'GerritVolumeSizeInGiB'
+
Outputs:
ClusterName:
Description: The name of the ECS cluster
diff --git a/single-master/cf-service.yml b/single-master/cf-service.yml
index 99cab14..fcfe842 100644
--- a/single-master/cf-service.yml
+++ b/single-master/cf-service.yml
@@ -285,47 +285,23 @@
awslogs-stream-prefix: !Ref EnvironmentName
Volumes:
- Name: !Ref 'GerritDbVolume'
- DockerVolumeConfiguration:
- Scope: shared
- Autoprovision: true
- Driver: local
- Labels:
- gerrit-db: !Join ['-', [!Ref EnvironmentName, !Ref GerritDbVolume]]
+ Host:
+ SourcePath: !Join ['/', ["/gerrit-mount-point", !Ref GerritDbVolume]]
- Name: !Ref 'GerritGitVolume'
- DockerVolumeConfiguration:
- Scope: shared
- Autoprovision: true
- Driver: local
- Labels:
- gerrit-git: !Join ['-', [!Ref EnvironmentName, !Ref GerritGitVolume]]
+ Host:
+ SourcePath: !Join ['/', ["/gerrit-mount-point", !Ref GerritGitVolume]]
- Name: !Ref 'GerritDataVolume'
- DockerVolumeConfiguration:
- Scope: shared
- Autoprovision: true
- Driver: local
- Labels:
- gerrit-data: !Join ['-', [!Ref EnvironmentName, !Ref GerritDataVolume]]
+ Host:
+ SourcePath: !Join ['/', ["/gerrit-mount-point", !Ref GerritDataVolume]]
- Name: !Ref 'GerritCacheVolume'
- DockerVolumeConfiguration:
- Scope: shared
- Autoprovision: true
- Driver: local
- Labels:
- gerrit-cache: !Join ['-', [!Ref EnvironmentName, !Ref GerritCacheVolume]]
+ Host:
+ SourcePath: !Join ['/', ["/gerrit-mount-point", !Ref GerritCacheVolume]]
- Name: !Ref 'GerritIndexVolume'
- DockerVolumeConfiguration:
- Scope: shared
- Autoprovision: true
- Driver: local
- Labels:
- gerrit-index: !Join ['-', [!Ref EnvironmentName, !Ref GerritIndexVolume]]
+ Host:
+ SourcePath: !Join ['/', ["/gerrit-mount-point", !Ref GerritIndexVolume]]
- Name: !Ref 'GerritLogsVolume'
- DockerVolumeConfiguration:
- Scope: shared
- Autoprovision: true
- Driver: local
- Labels:
- gerrit-logs: !Join ['-', [!Ref EnvironmentName, !Ref GerritLogsVolume]]
+ Host:
+ SourcePath: !Join ['/', ["/gerrit-mount-point", !Ref GerritLogsVolume]]
LoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer