Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automation for Alibaba cloud #703

Merged
merged 1 commit into from
Jan 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions test/check-cloud
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import composertest


class TestCloud(composertest.ComposerTestCase):
def test_alibaba(self):
self.runCliTest("/tests/cli/test_compose_alibaba.sh")

def test_aws(self):
self.runCliTest("/tests/cli/test_build_and_deploy_aws.sh")

Expand Down
124 changes: 124 additions & 0 deletions tests/cleanup/remove_old_objects_alibaba.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/bin/bash
# Script removes ECS Instances, Custom Images and OSS files older than
# HOURS_LIMIT (24 hours by default) from Alibaba cloud
#
. /usr/share/beakerlib/beakerlib.sh


rlJournalStart
rlPhaseStartSetup
ALI_DIR=`mktemp -d /tmp/alicloud.XXXXX`

if [ -z "$ALICLOUD_ACCESS_KEY" ]; then
rlFail "ALICLOUD_ACCESS_KEY is empty!"
else
rlLogInfo "ALICLOUD_ACCESS_KEY is configured"
fi

if [ -z "$ALICLOUD_SECRET_KEY" ]; then
rlFail "ALICLOUD_SECRET_KEY is empty!"
else
rlLogInfo "ALICLOUD_SECRET_KEY is configured"
fi

ALICLOUD_BUCKET="${ALICLOUD_BUCKET:-composer-test}"
rlLogInfo "ALICLOUD_BUCKET=$ALICLOUD_BUCKET"

# VMs older than HOURS_LIMIT will be deleted
HOURS_LIMIT="${HOURS_LIMIT:-24}"
TIMESTAMP=`date -u -d "$HOURS_LIMIT hours ago" '+%FT%T'`
rlLogInfo "HOURS_LIMIT=$HOURS_LIMIT"
rlLogInfo "TIMESTAMP=$TIMESTAMP"

for package in jq; do
if ! rlCheckRpm "$package"; then
rlRun -t -c "dnf -y install $package"
rlAssertRpm "$package"
fi
done

# use the CLI b/c Ansible modules are not yet upstream and are unreliable
TAR_FILE="aliyun-cli-linux-3.0.32-amd64.tgz"
curl -L https://github.com/aliyun/aliyun-cli/releases/download/v3.0.32/$TAR_FILE > $ALI_DIR/$TAR_FILE
tar -C $ALI_DIR/ -xzvf $ALI_DIR/$TAR_FILE
chmod a+x $ALI_DIR/aliyun

# configure
[ -d ~/.aliyun/ ] || mkdir ~/.aliyun/

if [ -f ~/.aliyun/config.json ]; then
rlLogInfo "Reusing existing ~/.aliyun/config.json"
else
rlLogInfo "Creating ~/.aliyun/config.json"
cat > ~/.aliyun/config.json << __EOF__
{
"current": "",
"profiles": [
{
"mode": "AK",
"access_key_id": "$ALICLOUD_ACCESS_KEY",
"access_key_secret": "$ALICLOUD_SECRET_KEY",
"region_id": "$ALICLOUD_REGION",
"output_format": "json",
"language": "en"
}
],
"meta_path": ""
}
__EOF__
fi

rlPhaseEnd

# Check all regions
for REGION_ID in `$ALI_DIR/aliyun Ecs DescribeRegions | jq -r '.Regions.Region[] | .RegionId'`; do
rlPhaseStartTest "Delete old VMs in region $REGION_ID"
for INSTANCE_ID in `$ALI_DIR/aliyun ecs DescribeInstances --RegionId $REGION_ID --InstanceName "Composer-Test*" | jq -r '.Instances.Instance[] | .InstanceId'`; do
CREATION_TIME=`$ALI_DIR/aliyun ecs DescribeInstanceAttribute --InstanceId $INSTANCE_ID | jq -r .CreationTime`
if [[ "$CREATION_TIME" < "$TIMESTAMP" ]]; then
rlLogInfo "Removing instance $REGION_ID/$INSTANCE_ID created at $CREATION_TIME < $TIMESTAMP"
rlRun -t -c "$ALI_DIR/aliyun ecs DeleteInstance --Force True --InstanceId $INSTANCE_ID"
else
rlLogInfo "Skipping instance $REGION_ID/$INSTANCE_ID created at $CREATION_TIME >= $TIMESTAMP"
fi
done
rlPhaseEnd

rlPhaseStartTest "Delete old Images in region $REGION_ID"
for IMAGE_ID in `$ALI_DIR/aliyun ecs DescribeImages --RegionId $REGION_ID --ImageName "Composer-Test*" | jq -r '.Images.Image[] | .ImageId'`; do
CREATION_TIME=`$ALI_DIR/aliyun ecs DescribeImages --ImageId $IMAGE_ID | jq -r '.Images.Image[] | .CreationTime'`
if [[ "$CREATION_TIME" < "$TIMESTAMP" ]]; then
rlLogInfo "Removing image $REGION_ID/$IMAGE_ID created at $CREATION_TIME < $TIMESTAMP"
rlRun -t -c "$ALI_DIR/aliyun ecs DeleteImage --Force True --ImageId $IMAGE_ID"
else
rlLogInfo "Skipping image $REGION_ID/$IMAGE_ID created at $CREATION_TIME >= $TIMESTAMP"
fi
done
rlPhaseEnd

rlPhaseStartTest "Delete composer key pairs in region $REGION_ID"
for KEY_NAME in `$ALI_DIR/aliyun ecs DescribeKeyPairs --KeyPairName "Composer-Test*" | jq -r '.KeyPairs.KeyPair[] | .KeyPairName'`; do
rlRun -t -c "$ALI_DIR/aliyun ecs DeleteKeyPairs --KeyPairNames '[\"$KEY_NAME\"]'"
done
rlPhaseEnd
done

rlPhaseStartTest "Delete old OSS objects"
all_objects=`$ALI_DIR/aliyun oss ls oss://$ALICLOUD_BUCKET/Composer-Test | awk 'NR > 1' | head -n -2`
while read date_f time_f tz_offset tz_name size_bytes storage_class etag filename_f; do
creation_date=`date -u -d "$date_f $time_f$tz_offset" '+%FT%T'`
if [[ "$creation_date" < "$TIMESTAMP" ]]; then
rlLogInfo "Removing old file $filename_f created at $creation_date < $TIMESTAMP"
rlRun -t -c "$ALI_DIR/aliyun oss rm $filename_f"
else
rlLogInfo "Skipping file $filename_f created at $creation_date >= $TIMESTAMP"
fi
done <<< "$all_objects"
rlPhaseEnd

rlPhaseStartCleanup
rlRun -t -c "rm -rf $ALI_DIR"
rlPhaseEnd

rlJournalEnd
rlJournalPrintText
197 changes: 197 additions & 0 deletions tests/cli/test_compose_alibaba.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
#!/bin/bash
# Note: execute this file from the project root directory

#####
#
# Make sure we can build an image and deploy it inside Alibaba cloud!
#
#####

set -e

. /usr/share/beakerlib/beakerlib.sh
. $(dirname $0)/lib/lib.sh

CLI="${CLI:-./src/bin/composer-cli}"


rlJournalStart
rlPhaseStartSetup
if [ -z "$ALICLOUD_ACCESS_KEY" ]; then
rlFail "ALICLOUD_ACCESS_KEY is empty!"
else
rlLogInfo "ALICLOUD_ACCESS_KEY is configured"
fi

if [ -z "$ALICLOUD_SECRET_KEY" ]; then
rlFail "ALICLOUD_SECRET_KEY is empty!"
else
rlLogInfo "ALICLOUD_SECRET_KEY is configured"
fi

ALICLOUD_BUCKET="${ALICLOUD_BUCKET:-composer-test}"
ALICLOUD_REGION="${ALICLOUD_REGION:-us-east-1}"

rlLogInfo "ALICLOUD_BUCKET=$ALICLOUD_BUCKET"
rlLogInfo "ALICLOUD_REGION=$ALICLOUD_REGION"

for package in jq; do
if ! rlCheckRpm "$package"; then
rlRun -t -c "dnf -y install $package"
rlAssertRpm "$package"
fi
done

ALI_DIR=`mktemp -d /tmp/alicloud.XXXXX`
# use the CLI b/c Ansible modules are not yet upstream and are unreliable
TAR_FILE="aliyun-cli-linux-3.0.32-amd64.tgz"
curl -L https://github.com/aliyun/aliyun-cli/releases/download/v3.0.32/$TAR_FILE > $ALI_DIR/$TAR_FILE
tar -C $ALI_DIR/ -xzvf $ALI_DIR/$TAR_FILE
chmod a+x $ALI_DIR/aliyun

# configure
[ -d ~/.aliyun/ ] || mkdir ~/.aliyun/

if [ -f ~/.aliyun/config.json ]; then
rlLogInfo "Reusing existing ~/.aliyun/config.json"
else
rlLogInfo "Creating ~/.aliyun/config.json"
cat > ~/.aliyun/config.json << __EOF__
{
"current": "",
"profiles": [
{
"mode": "AK",
"access_key_id": "$ALICLOUD_ACCESS_KEY",
"access_key_secret": "$ALICLOUD_SECRET_KEY",
"region_id": "$ALICLOUD_REGION",
"output_format": "json",
"language": "en"
}
],
"meta_path": ""
}
__EOF__
fi

rlPhaseEnd

rlPhaseStartTest "compose start"
rlAssertEquals "SELinux operates in enforcing mode" "$(getenforce)" "Enforcing"
UUID=`$CLI compose start example-http-server alibaba`
rlAssertEquals "exit code should be zero" $? 0

UUID=`echo $UUID | cut -f 2 -d' '`
rlPhaseEnd

rlPhaseStartTest "compose finished"
wait_for_compose $UUID
rlPhaseEnd

rlPhaseStartTest "Import image in Alibaba cloud"
rlRun -t -c "$CLI compose image $UUID"

rlRun -t -c "mv $UUID-disk.qcow2 Composer-Test-$UUID-disk.qcow2"
IMAGE="Composer-Test-$UUID-disk.qcow2"

# upload to OSS
rlRun -t -c "$ALI_DIR/aliyun oss cp --retry-count 20 $IMAGE oss://$ALICLOUD_BUCKET/$IMAGE"

# now import as machine image
# WARNING: DiskImageSize *MUST BE* 40 GiB. We don't need all of that but
# VMs fail to boot otherwise !!! Not sure why.
rlRun -t -c "$ALI_DIR/aliyun ecs ImportImage \
--OSType linux --Platform RedHat \
--Architecture x86_64 \
--DiskDeviceMapping.1.DiskImageSize 40 \
--DiskDeviceMapping.1.Format qcow2 \
--DiskDeviceMapping.1.OSSBucket $ALICLOUD_BUCKET \
--DiskDeviceMapping.1.OSSObject $IMAGE \
--ImageName $IMAGE"

# wait for status to become available
while [ `$ALI_DIR/aliyun ecs DescribeImages --ImageName $IMAGE --Status Available | jq .Images.Image | jq -r '.[0].ImageName'` == "null" ]; do
rlLogInfo "Waiting for import to complete ..."
sleep 60
done

rlRun -t -c "$ALI_DIR/aliyun ecs DescribeImages --ImageName $IMAGE"
IMAGE_ID=`$ALI_DIR/aliyun ecs DescribeImages --ImageName $IMAGE | jq .Images.Image | jq -r '.[0].ImageId'`

if [ "$IMAGE_ID" == "null" ]; then
rlFail "IMAGE_ID is empty!"
else
rlLogInfo "IMAGE_ID=$IMAGE_ID"
fi
rlPhaseEnd

rlPhaseStartTest "Start ECS instance"
INSTANCE_TYPE="ecs.n1.medium"

# generate & import new ssh key
KEY_NAME=Composer-Test-$UUID
SSH_KEY_DIR=`mktemp -d /tmp/composer-ssh-keys.XXXXXX`
rlRun -t -c "ssh-keygen -t rsa -N '' -f $SSH_KEY_DIR/id_rsa"
SSH_PUB_KEY=$(cat $SSH_KEY_DIR/id_rsa.pub)
rlRun -t -c "$ALI_DIR/aliyun ecs ImportKeyPair --KeyPairName $KEY_NAME --PublicKeyBody '$SSH_PUB_KEY'"

RELEASE_TIME=$(date -u -d "24 hours" '+%FT%TZ')

# SecurityGroup is composer-allow-ssh
# VPC is composer-vpc
response=$($ALI_DIR/aliyun ecs RunInstances --Amount 1 --ImageId $IMAGE_ID \
--InstanceType=$INSTANCE_TYPE --InstanceName Composer-Test-VM-$UUID \
--SecurityGroupId sg-0xi4w9isg0p1ytj1qbhf \
--VSwitchId vsw-0xi36w0a9l894vf2momfb \
--KeyPairName $KEY_NAME \
--InternetMaxBandwidthIn 5 --InternetMaxBandwidthOut 5 \
--AutoReleaseTime $RELEASE_TIME)
rlAssert0 "VM started successfully" $?
rlLogInfo "$response"

INSTANCE_ID=`echo "$response" | jq .InstanceIdSets.InstanceIdSet | jq -r '.[0]' `

until [ $($ALI_DIR/aliyun ecs DescribeInstanceAttribute --InstanceId $INSTANCE_ID | jq -r .Status | grep "Running\|Stopped") ]; do
sleep 30
rlLogInfo "Waiting for instance to start ..."
done

rlAssertEquals "Instance $INSTANCE_ID is Running" \
"$($ALI_DIR/aliyun ecs DescribeInstanceAttribute --InstanceId $INSTANCE_ID | jq -r .Status)" "Running"
rlRun -t -c "$ALI_DIR/aliyun ecs DescribeInstanceAttribute --InstanceId $INSTANCE_ID"

IP_ADDRESS="null"
while [ "$IP_ADDRESS" == "null" ]; do
rlLogInfo "IP_ADDRESS is not assigned yet ..."
sleep 30
IP_ADDRESS=`$ALI_DIR/aliyun ecs DescribeInstanceAttribute --InstanceId $INSTANCE_ID | jq -r .PublicIpAddress.IpAddress | jq -r '.[0]'`
done

rlLogInfo "Running INSTANCE_ID=$INSTANCE_ID with IP_ADDRESS=$IP_ADDRESS"
rlPhaseEnd

rlPhaseStartTest "Verify EC2 instance"
# cloud-init default config differs between RHEL and Fedora
CLOUD_USER="cloud-user"
if [ -f "/etc/fedora-release" ]; then
CLOUD_USER="fedora"
fi

# run generic tests to verify the instance
verify_image "$CLOUD_USER" "$IP_ADDRESS" "-i $SSH_KEY_DIR/id_rsa"
rlPhaseEnd

rlPhaseStartCleanup
rlRun -t -c "$ALI_DIR/aliyun ecs DeleteInstance --Force True --InstanceId $INSTANCE_ID"
rlRun -t -c "$ALI_DIR/aliyun ecs DeleteImage --Force True --ImageId $IMAGE_ID"
rlRun -t -c "$ALI_DIR/aliyun oss rm oss://$ALICLOUD_BUCKET/$IMAGE --force"
rlRun -t -c "$CLI compose delete $UUID"
rlRun -t -c "rm -rf $IMAGE $SSH_KEY_DIR $ALI_DIR"
# do this here to give time for the VM instance to be removed properly
# also don't fail if the key is still attached to an instance which is waiting
# to be desroyed. We're going to remove these keys in cleanup afterwards
$ALI_DIR/aliyun ecs DeleteKeyPairs --KeyPairNames "['$KEY_NAME']" || echo
rlPhaseEnd

rlJournalEnd
rlJournalPrintText