diff --git a/incubator/charts-repo/.gitignore b/incubator/charts-repo/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/incubator/charts-repo/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/incubator/charts-repo/README.md b/incubator/charts-repo/README.md new file mode 100644 index 0000000..8258527 --- /dev/null +++ b/incubator/charts-repo/README.md @@ -0,0 +1,43 @@ +# Manage a Helm Chart Repository using Minio and Kubeless + +## Create 'charts' topic + +```console +$ kubeless topic create charts +``` + +## Deploy Minio using Helm + +```console +$ helm install -n minio stable/minio --set minioConfig.kafka.enable=true,minioConfig.kafka.brokers="[\"kafka.kubeless:9092\"]",minioConfig.kafka.topic=charts +``` + +## Configure Minio client to connect to Minio and setup + +```console +$ mc config host add myminio $MINIO_HOST $MINIO_ACCESS_KEY $MINIO_SECRET_KEY +$ mc mb myminio/charts +$ mc policy download myminio/charts +$ mc events add myminio/charts arn:minio:sqs:us-east-1:1:kafka --events put --suffix .tgz +``` + +## Deploy this function + +```console +$ kubeless function deploy charts-repo-indexer --from-file indexer.js --handler indexer.handler --runtime nodejs8 --trigger-topic charts --dependencies package.json --env REPO_URL=$MINIO_HOST/charts,MINIO_ACCESS_KEY=$MINIO_ACCESS_KEY,MINIO_SECRET_KEY=$MINIO_SECRET_KEY +``` + +## Add a chart to the bucket + +```console +$ helm fetch stable/redis +$ mc cp redis*.tgz myminio/charts +``` + +## Add chart repository to Helm + +```console +$ helm repo add myminio $MINIO_HOST/charts +$ helm repo update +$ helm search myminio/ +``` diff --git a/incubator/charts-repo/indexer.js b/incubator/charts-repo/indexer.js new file mode 100644 index 0000000..2dbaa17 --- /dev/null +++ b/incubator/charts-repo/indexer.js @@ -0,0 +1,59 @@ +const Minio = require('minio') +const { exec, execSync } = require('child_process'); +const path = require('path'); +const fs = require('fs'); +const log = require('winston'); +const mutex = require('locks').createMutex(); + +const minioClient = new Minio.Client({ + endPoint: 'minio-minio-svc', + port: 9000, + secure: false, + accessKey: process.env.MINIO_ACCESS_KEY, + secretKey: process.env.MINIO_SECRET_KEY, +}); + +const helmInstall = ` +wget -q http://storage.googleapis.com/kubernetes-helm/helm-v2.5.1-linux-amd64.tar.gz +tar xzfv helm-v2.5.1-linux-amd64.tar.gz +/linux-amd64/helm init --client-only +` + +execSync(helmInstall, {stdio: 'inherit'}); + +module.exports = { + handler: (context) => { + context = JSON.parse(context); + let bucket = context.Records[0].s3.bucket.name; + let package = context.Records[0].s3.object.key; + let packageDir = fs.mkdtempSync('/tmp/'); + log.info(`Fetching ${package}`); + minioClient.fGetObject(bucket, package, path.join(packageDir, package), function(err) { + if (err) { + return log.error(err); + } + mutex.lock(() => { + log.info(`Acquired lock to process ${package}`); + minioClient.fGetObject(bucket, 'index.yaml', path.join(packageDir, 'index.yaml'), function(err) { + let args = ''; + if (err) { + log.info(`Generating index for the first time with ${package}`); + } else { + log.info(`Re-generating index to add ${package}`); + args = '--merge index.yaml'; + } + execSync(`/linux-amd64/helm repo index --url ${process.env.REPO_URL} ${args} .`, {stdio: 'inherit', cwd: packageDir}); + log.info(`Uploading regenerated index to bucket`); + minioClient.fPutObject(bucket, 'index.yaml', path.join(packageDir, 'index.yaml'), 'application/octet-stream', function(err, etag) { + if (err) { + return log.error(err); + } + execSync(`rm -rf ${packageDir}`, {stdio: 'inherit'}); + log.info(`Successfully uploaded regenerated index`); + mutex.unlock(); + }); + }); + }); + }); + } +}; diff --git a/incubator/charts-repo/package.json b/incubator/charts-repo/package.json new file mode 100644 index 0000000..aa060d0 --- /dev/null +++ b/incubator/charts-repo/package.json @@ -0,0 +1,17 @@ +{ + "name": "charts-repo", + "version": "1.0.0", + "description": "", + "main": "indexer.js", + "dependencies": { + "locks": "^0.2.2", + "minio": "^3.2.0", + "winston": "^2.3.1" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +}