### Use Bash shell script to make new resource type for Concourse CI ##### https://hackmd.io/@fourdollars/MakeResourceType --- ## Who am I? FourDollars aka $4 - Debian Developer / Ubuntu Contributing Developer / GNOME Emeritus Member / Canonical Employee - Vim :heart: [Plurk](https://www.plurk.com/fourdollars) ---- [LinkedIn](https://www.linkedin.com/in/fourdollars/) --- ## What is Concourse CI? https://concourse-ci.org/ ---- Use YAML to define the pipelines <iframe width="100%" height="500" src="https://ci.concourse-ci.org/" frameborder="0"></iframe> https://ci.concourse-ci.org/ ---- ## 一些使用上的條件限制 * 只支援 Docker container * 只支援 amd64/x86_64 架構 * pipeline 不支援 if else 分支 * 要熟悉 YAML 及 JSON 語法 * 學習曲線高 ([官方自己說的](https://concourse-ci.org/docs.html)) ---- 簡介請參考 [Introducing Concourse CI](https://hackmd.io/@fourdollars/introducing-concourse-ci) by $4 --- All following examples are available on [![GitHub: fourdollars/concourse-demo](https://img.shields.io/badge/GitHub-fourdollars%2Fconcourse%E2%80%90demo-white.svg?style=flat-square&logo=github)](https://github.com/fourdollars/concourse-demo/) --- ## Introduce WebDAV resource [![GitHub: fourdollars/webdav-resource](https://img.shields.io/badge/GitHub-fourdollars%2Fwebdav%E2%80%90resource-white.svg?style=flat-square&logo=github)](https://github.com/fourdollars/webdav-resource/) ![](https://i.imgur.com/yZYoAA7.png) ---- pipeline.yml ```yaml= resource_types: - name: webdav type: registry-image source: repository: ghcr.io/fourdollars/webdav-resource defaults: domain: webdav username: webdav password: webdav ssl: false resources: - name: demo-storage type: webdav icon: nas source: path: demo - name: ubuntu-focal type: registry-image icon: ubuntu source: repository: ubuntu tag: focal jobs: - name: check-demo-message plan: - get: ubuntu-focal - get: demo-storage trigger: true - task: check-message image: ubuntu-focal config: platform: linux inputs: - name: demo-storage run: path: cat args: - demo-storage/msg.log ``` ---- # Live Demo ---- 入門請參考 TOSSUG [2021/05/04 Concourse CI 幼幼班](https://hackmd.io/@tossug/rJNzwsFPd) --- ## Make a simple HTTP resource ---- ### Goal: Print the content of HTTP file when it changed. ```shell $ python3 -m http.server 9527 $ date > msg.log $ curl http://0.0.0.0:9527/msg.log ``` ```yaml resources: - name: message type: http icon: nas source: url: http://0.0.0.0:9527/msg.log ``` ---- ## How to generate the digest? ```shell $ curl --head http://0.0.0.0:9527/msg.log HTTP/1.0 200 OK Server: SimpleHTTP/0.6 Python/3.8.10 Date: Tue, 13 Jul 2021 14:12:18 GMT Content-type: application/octet-stream Content-Length: 53 Last-Modified: Tue, 13 Jul 2021 13:59:01 GMT $ curl --head http://0.0.0.0:9527/msg.log | sha256sum ec8af3a926d2fe396d9b8d1d0e7a077bfa064937a9d02158321d1... ``` ---- ## This digest is unreliable. ```shell $ curl --head http://0.0.0.0:9527/msg.log | sha256sum efdaa9fc9f4b5f5d6d0106500621e7c5193efd1288785040809e0... $ curl --head http://0.0.0.0:9527/msg.log | sha256sum a326c45b04b5a756906882cdac6477689a72fed551db8afb6d565... $ curl --head http://0.0.0.0:9527/msg.log | sha256sum 8ab03fab7a6d5a86a290f54aa5b32978e0240517f757ae50a9cd6... ``` ---- ## Generate the reliable digest Find out the **immutable** parts ```shell $ curl --head http://0.0.0.0:9527/msg.log | \ grep -e ^Last-Modified -e ^Content-Length Content-Length: 53 Last-Modified: Tue, 13 Jul 2021 13:59:01 GMT $ curl --head http://0.0.0.0:9527/msg.log | \ grep -e ^Last-Modified -e ^Content-Length | sha256sum c3327a0c5bccfb7524f320bea52861c56542c9fd5e56603e3825c83... ``` --- ## Let's make the simple HTTP resource ---- ### Dockerfile ```dockerfile FROM alpine:latest RUN apk update RUN apk upgrade RUN apk add bash jq curl # check step ADD /check /opt/resource/check # put step ADD /out /opt/resource/out # get step ADD /in /opt/resource/in # make sure they are executable RUN chmod +x /opt/resource/* ``` * bash: deal with shell script * jq: deal with JSON * curl: deal with HTTP ---- ### Trinity: check / in / out ```shell $ ln -s in check $ ln -s in out $ vim in ``` Template ```bash= #!/bin/bash # Bash strict mode set -euo pipefail IFS=$'\n\t' # make stdout available as fd 3 for the result exec 3>&1 # redirect all output to stderr for logging exec 1>&2 # read the json from /dev/stdin and save to /tmp/input.json jq -M -S . < /dev/stdin > /tmp/input.json # '-M' monochrome (don't colorize JSON); # '-S' sort keys of objects on output; case "$0" in ('/opt/resource/check') json='[]' ;; ('/opt/resource/in') cd "$1" # /tmp/build/get json='{}' ;; ('/opt/resource/out') cd "$1" # /tmp/build/put json='{}' # noop ;; esac # output the json to fd 3 jq -n "$json" >&3 # '-n' Don't read from stdin ``` ---- ### Read the url from json ```bash # '-S' sort keys of objects on output; url=$(jq -r .source.url < /tmp/input.json) case "$0" in ``` ```yaml resources: - name: message type: http icon: nas source: url: http://0.0.0.0:9527/msg.log ``` ---- ### Generate the reliable digest in check step ```bash=17 case "$0" in ('/opt/resource/check') sha256=$(curl --head "$url" \ | grep -i -e ^Last-Modified -e ^Content-Length \ | sha256sum | awk '{print $1}') json=$(cat <<ENDLINE [ { "digest": "sha256:$sha256" } ] ENDLINE ) ;; ``` ---- ### Download the file in get step ```bash=21 ('/opt/resource/in') cd "$1" # /tmp/build/get curl --dump-header /tmp/header.log "$url" > "$(basename "$url")" sha256=$(grep -i -e ^Last-Modified -e ^Content-Length /tmp/header.log \ | sha256sum | awk '{print $1}') length=$(grep -i -e ^Content-Length /tmp/header.log \ | awk '{print $2}' | tr -d '\r') modified=$(grep -i -e ^Last-Modified /tmp/header.log \ | cut -d ' ' -f 2- | tr -d '\r') json=$(cat <<ENDLINE { "version": { "digest": "sha256:$sha256" }, "metadata": [ { "name": "url", "value": "$url" }, { "name": "Last-Modified", "value": "$modified" }, { "name": "Content-Length", "value": "$length" } ] } ENDLINE ) ;; ``` ---- 實作請參考 [1.9.1 Implementing a Resource Type](https://concourse-ci.org/implementing-resource-types.html) --- ## Let's build the Docker image for the simple HTTP resource ![](https://i.imgur.com/Bh1Qng7.png) ---- #### pipeline.yml ```yaml= resources: - name: concourse-demo type: git source: uri: https://github.com/fourdollars/concourse-demo branch: coscup - name: resource-image type: docker-image source: repository: registry:5000/simple-http-resource username: registry password: registry insecure_registries: [ "registry:5000" ] jobs: - name: build-simple-http-resource plan: - get: concourse-demo trigger: true - put: resource-image params: build: concourse-demo/simple-http-resource ``` ---- # Live Demo --- ## Let's use the simple HTTP resource ![](https://i.imgur.com/ANzEV6a.png) ---- #### pipeline.yml ```yaml= resource_types: - name: simple-http type: docker-image source: repository: registry:5000/simple-http-resource username: registry password: registry insecure_registries: [ "registry:5000" ] resources: - name: message icon: nas type: simple-http source: url: https://people.debian.org/~fourdollars/coscup-2021.log - name: ubuntu-focal type: registry-image icon: ubuntu source: repository: ubuntu tag: focal jobs: - name: check-message plan: - get: ubuntu-focal - get: message trigger: true - task: check image: ubuntu-focal config: platform: linux inputs: - name: message run: path: cat args: - message/coscup-2021.log ``` ---- # Live Demo --- # The End ## Q&A
{"metaMigratedAt":"2023-06-16T03:25:28.370Z","metaMigratedFrom":"YAML","title":"Use Bash shell script to make new resource type for Concourse CI","breaks":true,"description":"View the slide with \"Slide Mode\".","slideOptions":"{\"transition\":\"slide\",\"allottedMinutes\":30}","contributors":"[{\"id\":\"bf86f028-d66e-4ad3-b300-1ac45ed078ed\",\"add\":11609,\"del\":5654}]"}
    1848 views