AWS CodeBuild local cache failing to actually cache? - aws-codebuild

I've been trying to get AWS CodeBuild's local cache to work and for the life of me I can't get even the most basic cache to work. My ultimate goal is to cache Gradle artifacts, as discussed here.
But because I couldn't get that to work, I tried an even simpler test, where I try to cache the directory /root/foo with a file counter.txt that I increment each build. My expectation is that if I run subsequent builds within a few minutes of each other, I would see "2", "3", etc in the logs. But the reality is that despite the symlink being established, the next build never sees the previous counter.txt file, which suggests to me something is very broken.
Can anyone confirm that their local cache is actually working in CodeBuild? I'm starting to wonder if the feature is presently broken! Or am I totally misunderstanding what it is supposed to do?
buildspec.yml:
version: 0.2
phases:
install:
runtime-versions:
java: corretto8
build:
commands:
- pwd
- ls -l /root/
- ls -l /root/foo/
- ./cache-test.sh
- ls -l /root/
- ls -l /root/foo/
cache:
paths:
- '/root/foo/*'
cache-test.sh:
#!/bin/bash
if [ -d "/root/foo" ]; then
C=$(cat /root/foo/count.txt)
C=$((C + 1))
echo "*********************************"
echo "*********************************"
echo "Incrementing counter to $C"
echo $C > /root/foo/count.txt
echo "*********************************"
echo "*********************************"
else
mkdir /root/foo
echo "*********************************"
echo "*********************************"
echo "File not found, starting count at 1"
echo "*********************************"
echo "*********************************"
echo 1 > /root/foo/count.txt
fi
CodeBuild output: (same output even when executed in quick succession)
[Container] 2019/11/10 22:35:08 Waiting for agent ping
[Container] 2019/11/10 22:35:10 Waiting for DOWNLOAD_SOURCE
[Container] 2019/11/10 22:35:10 Phase is DOWNLOAD_SOURCE
[Container] 2019/11/10 22:35:10 CODEBUILD_SRC_DIR=/codebuild/output/src905503483/src
[Container] 2019/11/10 22:35:10 YAML location is /codebuild/output/src905503483/src/buildspec.yml
[Container] 2019/11/10 22:35:10 No commands found for phase name: INSTALL
[Container] 2019/11/10 22:35:10 Processing environment variables
[Container] 2019/11/10 22:35:10 Moving to directory /codebuild/output/src905503483/src
[Container] 2019/11/10 22:35:10 MkdirAll: /codebuild/local-cache/custom/de68c9f22ae028d4e4dfb0d11bbb481053d28b1373db0d6a56ebee0416bf13b2/root/foo
[Container] 2019/11/10 22:35:10 Symlinking: /root/foo => /codebuild/local-cache/custom/de68c9f22ae028d4e4dfb0d11bbb481053d28b1373db0d6a56ebee0416bf13b2/root/foo
[Container] 2019/11/10 22:35:10 Registering with agent
[Container] 2019/11/10 22:35:10 Phases found in YAML: 2
[Container] 2019/11/10 22:35:10 BUILD: 6 commands
[Container] 2019/11/10 22:35:10 INSTALL: 0 commands
[Container] 2019/11/10 22:35:10 Phase complete: DOWNLOAD_SOURCE State: SUCCEEDED
[Container] 2019/11/10 22:35:10 Phase context status code: Message:
[Container] 2019/11/10 22:35:11 Entering phase INSTALL
[Container] 2019/11/10 22:35:11 Running command echo "Installing corretto(OpenJDK) version 8 ..."
Installing corretto(OpenJDK) version 8 ...
[Container] 2019/11/10 22:35:11 Running command export JAVA_HOME="$JAVA_8_HOME"
[Container] 2019/11/10 22:35:11 Running command export JRE_HOME="$JRE_8_HOME"
[Container] 2019/11/10 22:35:11 Running command export JDK_HOME="$JDK_8_HOME"
[Container] 2019/11/10 22:35:11 Running command for tool_path in "$JAVA_8_HOME"/bin/* "$JRE_8_HOME"/bin/*;
do tool=`basename "$tool_path"`;
if [ $tool != 'java-rmi.cgi' ];
then
rm -f /usr/bin/$tool /var/lib/alternatives/$tool \
&& update-alternatives --install /usr/bin/$tool $tool $tool_path 20000;
fi;
done
[Container] 2019/11/10 22:35:11 Phase complete: INSTALL State: SUCCEEDED
[Container] 2019/11/10 22:35:11 Phase context status code: Message:
[Container] 2019/11/10 22:35:11 Entering phase PRE_BUILD
[Container] 2019/11/10 22:35:11 Phase complete: PRE_BUILD State: SUCCEEDED
[Container] 2019/11/10 22:35:11 Phase context status code: Message:
[Container] 2019/11/10 22:35:11 Entering phase BUILD
[Container] 2019/11/10 22:35:11 Running command pwd
/codebuild/output/src905503483/src
[Container] 2019/11/10 22:35:11 Running command ls -l /root/
total 4
lrwxrwxrwx 1 root root 103 Nov 10 22:35 foo -> /codebuild/local-cache/custom/de68c9f22ae028d4e4dfb0d11bbb481053d28b1373db0d6a56ebee0416bf13b2/root/foo
[Container] 2019/11/10 22:35:11 Running command ls -l /root/foo/
total 0
[Container] 2019/11/10 22:35:11 Running command ./cache-test.sh
cat: /root/foo/count.txt: No such file or directory
*********************************
*********************************
Incrementing counter to 1
*********************************
*********************************
[Container] 2019/11/10 22:35:11 Running command ls -l /root/
total 4
lrwxrwxrwx 1 root root 103 Nov 10 22:35 foo -> /codebuild/local-cache/custom/de68c9f22ae028d4e4dfb0d11bbb481053d28b1373db0d6a56ebee0416bf13b2/root/foo
[Container] 2019/11/10 22:35:11 Running command ls -l /root/foo/
total 4
-rw-r--r-- 1 root root 2 Nov 10 22:35 count.txt
[Container] 2019/11/10 22:35:11 Phase complete: BUILD State: SUCCEEDED
[Container] 2019/11/10 22:35:11 Phase context status code: Message:
[Container] 2019/11/10 22:35:11 Entering phase POST_BUILD
[Container] 2019/11/10 22:35:11 Phase complete: POST_BUILD State: SUCCEEDED
[Container] 2019/11/10 22:35:11 Phase context status code: Message:
CodeBuild project JSON:
{
"projects": [
{
"name": "test-project",
"arn": "arn:aws:codebuild:us-east-2:xxx:project/xxx",
"source": {
"type": "CODEPIPELINE",
"insecureSsl": false
},
"secondarySourceVersions": [],
"artifacts": {
"type": "CODEPIPELINE",
"name": "test-project",
"packaging": "NONE",
"encryptionDisabled": false
},
"secondaryArtifacts": [],
"cache": {
"type": "LOCAL",
"modes": [
"LOCAL_SOURCE_CACHE",
"LOCAL_CUSTOM_CACHE"
]
},
"environment": {
"type": "LINUX_CONTAINER",
"image": "aws/codebuild/amazonlinux2-x86_64-standard:1.0",
"computeType": "BUILD_GENERAL1_SMALL",
"environmentVariables": [],
"privilegedMode": false,
"imagePullCredentialsType": "CODEBUILD"
},
"serviceRole": "arn:aws:iam::xxx:role/service-role/xxx",
"timeoutInMinutes": 60,
"queuedTimeoutInMinutes": 480,
"encryptionKey": "arn:aws:kms:us-east-2:xxx:alias/aws/s3",
"tags": [],
"created": 1573364156.631,
"lastModified": 1573423155.674,
"badge": {
"badgeEnabled": false
},
"logsConfig": {
"cloudWatchLogs": {
"status": "ENABLED",
"groupName": "xxx",
"streamName": "xxx"
},
"s3Logs": {
"status": "DISABLED",
"encryptionDisabled": false
}
}
}
],
"projectsNotFound": []
}

I have been trying to make the cache work myself with limited success.
Not from any public source, but these are some observations:
The cache will only be avilable if the build time is more than 5 minutes.
Cache can be used if the new build is successfully placed on the same build host.
Cache can be used if the new build is being run within 5-15 minutes of the last build. Cache may stay available based on the last build time with a max of 15 minutes.
Despite builds exceeding 5 minutes, the cache may not always work probably due to build being placed on different build host.
Additionally, in the case where the cache speeds up the new build to below 5 minutes, that build will not be cached resulting in subsequent miss.
While I trust CodeBuild engineers had good reasons to design it this way, the above limitations renders this local cache functionality of limited use in my opinion.

The documentation isn't exactly clear, but AWS CodeBuild Local cache can only cache directories (as of time of writing). This is slightly confusing because the AWS CodeBuild buildspec specification allows the path to be individual files or a wildcard, but in reality specifying a file will yield an error.
Unable to initialize cache download: only directories can be cached locally: ...
In your example you use specify the cache as
cache:
paths:
- '/root/foo/*'
Where * would refer to all individual files and folders inside foo but only folders would be cached.
Specifying the entire directory should work
cache:
paths:
- /root/foo/

Related

Cypress is not running in parallel on AWS

I'm trying to configure Parralel testing on AWS with Cypress. I have read the documentation from here and here, but nothing seems to work.
In my Buildspec I have the following:
## buildspec.yml
version: 0.2
env:
variables:
S3_BUCKET: {...}
SLACK_WEBHOOK: {...}
parameter-store:
CYPRESS_EMAIL: {...}
CYPRESS_LOGINURL: {...}
CYPRESS_MYPWD: {...}
## AWS CodeBuild Batch configuration
## https://docs.aws.amazon.com/codebuild/latest/userguide/batch-build-buildspec.html
batch:
fast-fail: false
build-list:
- identifier: {...}
env:
variables:
IMAGE: public.ecr.aws/cypress-io/cypress/browsers:node14.17.0-chrome88-ff89
build-matrix:
static:
ignore-failure: false
env:
type: LINUX_CONTAINER
privileged-mode: true
compute-type: BUILD_GENERAL1_MEDIUM
dynamic:
env:
compute-type:
- BUILD_GENERAL1_MEDIUM
image:
- public.ecr.aws/cypress-io/cypress/browsers:node14.17.0-chrome88-ff89
variables:
CY_GROUP_SPEC:
- "Machine 1|chrome|cypress/e2e/account-access/*"
- "Machine 2|chrome|cypress/e2e/settings/*"
- "Machine 3|chrome|cypress/tests/mail-accounts/*"
WORKERS:
- 1
- 2
- 3
phases:
install:
runtime-versions:
nodejs: latest
commands:
- echo $CY_GROUP_SPEC
- CY_GROUP=$(echo $CY_GROUP_SPEC | cut -d'|' -f1)
- CY_BROWSER=$(echo $CY_GROUP_SPEC | cut -d'|' -f2)
- CY_SPEC=$(echo $CY_GROUP_SPEC | cut -d'|' -f3)
- npm i
pre_build:
commands:
- TIME=$(date +"%Y%m%d_%H%M%S")
- sudo apt-get update -y && apt-get install jq -y
build:
on-failure: CONTINUE
commands:
- curl -X POST --data-urlencode "payload={\"channel\":\"#qa-notifications\",\"username\":\"mailshake-qa\",\"text\":\"Cypress tests starting...\",\"icon_emoji\":\":star:\"}" ${SLACK_WEBHOOK}
- npx cypress run --record --key {...} --parallel --browser "$CY_BROWSER" --ci-build-id $CODEBUILD_INITIATOR --group "$CY_GROUP" --spec "$CY_SPEC"
post_build:
commands:
{...}
When I run cypress on AWS it seems CY_GROUP_SPEC: is being ignore, and I get in return empty strings.
enter image description here
Any help?
I checked the indentation, and it looks good
I checked into this AWS documentation about having multiple buildspec
My solution to this was the following:
On AWS CodeBuild, do the following:
Navigate to the CodeBuild console
Select the project
Click "Edit" -- > "Batch Configuration"
Create "New service Role" -- enter the name
Leave everything optional
Click "Update batch configuration"
Start the Build
Then, do the following:
Navigate to the Pipeline
Select my Cypress Pipeline
Click "Edit"
Click on "Edit" button for my "Build" stage
Click on "Edit" button for my specific build {In this case, I only have one build stage}
And then set Build type to "Batch build" and turn on the checkbox "Combine all artifacts from batch into a single location"
You will have to update the WORKER in your YML by leaving only - 1 not multiple WORKERS as is indicated in Cypress documentation, otherwise, the same test will run multiple times. More info here

how to use npm in ansible

This is my main.yml file in task:
- name: Use npm
shell: >
/bin/bash -c "source $HOME/.nvm/nvm.sh && nvm use 16.16.0"
become: yes
become_user: root
- name: Run build-dev
shell: |
cd /home/ec2-user/ofiii
npm install
npm run build-dev
become: yes
become_user: root
when: platform == "dev"
And the output when running the script:
fatal: [172.31.200.13]: FAILED! => {
"changed": true,
"cmd": "cd /home/ec2-user/ofiii\nnpm install\nnpm run build-stag\n",
"delta": "0:00:00.061363",
"end": "2022-11-09 09:45:17.917829",
"msg": "non-zero return code",
"rc": 127,
"start": "2022-11-09 09:45:17.856466",
"stderr": "/bin/sh: line 1: npm:命令找不到\n/bin/sh: line 2: npm:命令找不到",
"stderr_lines": ["/bin/sh: line 1: npm:命令找不到", "/bin/sh: line 2: npm:命令找不到"],
"stdout": "",
"stdout_lines": []
}
the error is "npm:command not found" but I am really sure about the installation and the path to be set appropriatelly in the machine, the thing that I doubting is the script
I don't know how to modify my script,I tried to use npm module, but I failed
The problem is that each task environment is separate and you are setting nvm environment in a separate task.
The "Run build-dev" knows nothing about the paths set up from "Use npm"
I'd suggest combining these two tasks, with a few additional changes explained below:
- name: Run build-dev
shell: |
source $HOME/.nvm/nvm.sh
nvm use 16.16.0
npm install
npm run build-dev
args:
executable: /bin/bash
chdir: /home/ec2-user/ofiii
become: yes
become_user: root
when: platform == "dev"
Additional changes:
Using bash -c "..." in a shell module would result /bin/sh -c "/bin/bash -c '...'", it's better to use executable: /bin/bash instead
Shell module has chdir argument to specify the directory the script to run at
Check shell module documentation for other arguments and examples.

semantic-release: trigger chore(release) only on finished pipeline

I'm (mis)using semantic-release when building a C++ application in a GitLab CI.
My config is quite minimal
.releaserc.json
{
"branches": ["main", "develop"],
"plugins": [
"#semantic-release/commit-analyzer",
"#semantic-release/gitlab",
"#semantic-release/release-notes-generator",
[
"#semantic-release/changelog",
{
"changelogFile": "public/CHANGELOG.md"
}
],
[
"#semantic-release/git",
{
"assets": ["public/CHANGELOG.md"]
}
]
]
}
In the GitLab Ci, I have a couple of stages
Versioning -> Build -> Test -> Deploy
Versioning
version:
tags:
- macOS
stage: version
script:
- export PATH=$PATH:/usr/local/bin
# Configure semantic-release
- npm install
- npm ci --cache .npm --prefer-offline
- |
{
echo "#${CI_PROJECT_ROOT_NAMESPACE}:registry=${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/npm/"
echo "${CI_API_V4_URL#https?}/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=\${CI_JOB_TOKEN}"
} | tee -a .npmrc
- npm run semantic-release
- VERSION=$(grep -i -ow '\d\.\d\.\d' public/CHANGELOG.md | head -1)
- echo $VERSION > public/VERSION.txt
- echo $VERSION
artifacts:
name: "Changelog"
paths:
- public/*
Build relies on the Artifacts of Versioning, because it needs to add the current version to cmake. And yes, I'm grepping the version number from the change log, don't judge me :D
Works fine, but semantic-release is creating the tag right in the version stage. This could lead to problems, if the pipeline fails. Re-running a failed pipeline should result in an error "semantic-release: tag already exists".
is there any way to create the tag in a seperate stage at the very end, only if the rest of the pipeline succeeded?
Thanks!

Vue deployment to Heroku with CircleCI failing: fatal: Not a git repository (or any of the parent directories): .git

Having trouble deploying to HEROKU with CircleCI. I have already tested deploying git push heroku master to heroku manually, which is working. However when I use CircleCI, deployment no longer works.
Github repo url: https://github.com/dulerong/vue-test-circleci
I have set HEROKU environment variables in CircleCI project setting.
HEROKU_API_KEY=my_key
HEROKU_APP_NAME=my_app_name
Error message follows.
#!/bin/bash -eo pipefail
if false;then
force="-f"
fi
heroku_url="https://heroku:$HEROKU_API_KEY#git.heroku.com/$HEROKU_APP_NAME.git"
if [ -n "$CIRCLE_BRANCH" ]; then
git push $force $heroku_url $CIRCLE_BRANCH:main
elif [ -n "$CIRCLE_TAG" ]; then
git push $force $heroku_url $CIRCLE_TAG^{}:main
else
echo "No branch or tag found."
exit 1
fi
fatal: Not a git repository (or any of the parent directories): .git
Exited with code exit status 128
CircleCI received exit code 128
Below is my circleCI config.yml
version: 2.1
orbs:
heroku: circleci/heroku#1.2.5
jobs:
build-job:
working_directory: ~/repo
docker:
- image: circleci/node:12.18.2
steps:
- checkout
- run:
name: Install dependencies
command: npm install
- run:
name: Build
command: npm run build
- save_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
paths:
- ./node_modules
- run:
name: lint
command: npm run lint
- run:
name: test
command: npm run test:unit
deploy-job:
working_directory: ~/repo
docker:
- image: circleci/node:12.18.2
steps:
- attach_workspace:
at: ~/repo
- heroku/deploy-via-git
workflows:
version: 2.1
deploy:
jobs:
- build-job
- deploy-job:
requires:
- build-job
filters:
branches:
only: master
I have linked CircleCI to my Github repo
I have created .circleci folder config.yml
I have created an app on heroku, which works when I deploy manually
The build part of my CircleCI works, however deployment does not work
Any help is appreciated, thanks in advance.
Found out what I was missing.
- checkout
I was missing this line of code in my deploy-job. Hence after changing the deploy-job yml config code to following, everything worked.
deploy-job:
working_directory: ~/repo
docker:
- image: circleci/node:12.18.2
steps:
- checkout<--- INSERT THIS CODE HERE!!!!
- attach_workspace:
at: ~/repo
- heroku/deploy-via-git
Reason: checkout command leads CircleCI to the root directory of your project. Hence without this line of code, you're looking at a folder directory that's not even the root of your project.
Other useful command include
- run:
name: show directory
command: pwd
- run:
name: look in directory
command: ls -ltr
If you place those commands beneath checkouk, and look into the job progress in your CircleCI project, you can actually see which directory CircleCI is looking at, during that exact moment, very useful to check which directory CircleCI is working in. I put in those two commands and found out that my CircleCI was not looking at the root directory, hence discovering my problem.
Took me a few hours to figure this out!!!

Selenium (Docker, python, behave) takes hours to complete in CI

Tests are written with python behave and executed with Docker. Locally on Mac/Windows/Linux all 110 test steps complete under 4 minutes using the same sites whereas on CI agent (AWS) it takes 120-160 mins. Video showed that browser is spinning for about 4 minutes between steps. Is there a way to debug selenium to find out what resource is loading slow?
Selenium DEBUG logging is not helpful. After submit it took 4 minutes for a POST request to complete:
04-Apr-2018 20:13:01 DEBUG:selenium.webdriver.remote.remote_connection:POST http://127.0.0.1:4444/wd/hub/session/a6975e2107e574693fb48f21420c1850/element {"using": "id", "value": "submit", "sessionId": "a6975e2107e574693fb48f21420c1850"}
04-Apr-2018 20:13:01 DEBUG:selenium.webdriver.remote.remote_connection:Finished Request
04-Apr-2018 20:13:01 DEBUG:selenium.webdriver.remote.remote_connection:POST http://127.0.0.1:4444/wd/hub/session/a6975e2107e574693fb48f21420c1850/element/0.7198908368495902-4/click {"id": "0.7198908368495902-4", "sessionId": "a6975e2107e574693fb48f21420c1850"}
04-Apr-2018 20:17:00 DEBUG:selenium.webdriver.remote.remote_connection:Finished Request
docker-compose.yml:
version: '3.4'
services:
test:
build:
context: .
image: qa-automation
network_mode: host
environment:
LOCAL: "false"
BROWSER: "${TEST_BROWSER:-chrome}"
SERVER: "${TEST_URL:-https://example.com}"
selenium:
image: elgalu/selenium:3.11.0-p5
shm_size: 2g
ports:
- 4444:24444
- 6000:25900
environment:
SCREEN_WIDTH: 1920
SCREEN_HEIGHT: 1080
TZ: "US/Central"
VIDEO_FILE_NAME: "${TEST_BROWSER:-chrome}"
volumes:
- ./target/videos:/videos
Dockerfile:
FROM python:3.6.4-alpine3.7
# Install utilities
RUN apk --update --no-cache add bash curl git && rm -rf /var/cache/apk/*
ENV PYTHONUNBUFFERED 1
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
# see .dockerignore
COPY . .
ENTRYPOINT ["bin/docker-entrypoint.sh"]
CMD ["behave"]
requirements.txt:
appdirs==1.4.3
behave==1.2.6
packaging==16.8
pyparsing==2.2.0
requests==2.13.0
selenium==3.11.0
six==1.11.0
test.sh:
#!/usr/bin/env bash
docker-compose up -d selenium
docker-compose exec selenium wait_all_done 30s
docker-compose exec selenium start-video
# run tests
docker-compose build test
docker-compose run test bash -c "behave"
ret_code=$?
echo "===== Auto Tests COMPLETED ====="
# clean up containers
docker-compose exec selenium stop-video
docker-compose exec selenium stop
docker-compose down
exit $ret_code