Showing preview only (969K chars total). Download the full file or copy to clipboard to get everything.
Repository: skippbox/kubeless
Branch: master
Commit: af81a12a4b55
Files: 273
Total size: 24.9 MB
Directory structure:
gitextract_a4vhstu0/
├── .circleci/
│ └── config.yml
├── .github/
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── gcloud.json.enc
│ └── issue_template.md
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── OWNERS
├── README.md
├── cmd/
│ ├── function-controller/
│ │ └── function-controller.go
│ └── kubeless/
│ ├── autoscale/
│ │ ├── autoscale.go
│ │ ├── autoscaleCreate.go
│ │ ├── autoscaleDelete.go
│ │ ├── autoscaleList.go
│ │ ├── autoscaleList_test.go
│ │ └── autoscale_test.go
│ ├── completion/
│ │ └── completion.go
│ ├── function/
│ │ ├── call.go
│ │ ├── delete.go
│ │ ├── deploy.go
│ │ ├── describe.go
│ │ ├── function.go
│ │ ├── function_test.go
│ │ ├── list.go
│ │ ├── list_test.go
│ │ ├── logs.go
│ │ ├── top.go
│ │ ├── top_test.go
│ │ └── update.go
│ ├── getserverconfig/
│ │ └── getServerConfig.go
│ ├── kubeless.go
│ ├── topic/
│ │ ├── topic.go
│ │ ├── topicCreate.go
│ │ ├── topicDelete.go
│ │ ├── topicList.go
│ │ └── topicPublish.go
│ ├── trigger/
│ │ ├── cronjob/
│ │ │ ├── create.go
│ │ │ ├── cronjob_trigger.go
│ │ │ ├── delete.go
│ │ │ ├── list.go
│ │ │ └── update.go
│ │ ├── http/
│ │ │ ├── create.go
│ │ │ ├── delete.go
│ │ │ ├── http_trigger.go
│ │ │ ├── list.go
│ │ │ └── update.go
│ │ ├── kafka/
│ │ │ ├── create.go
│ │ │ ├── delete.go
│ │ │ ├── kafka_trigger.go
│ │ │ ├── list.go
│ │ │ └── update.go
│ │ ├── kinesis/
│ │ │ ├── create.go
│ │ │ ├── delete.go
│ │ │ ├── kinesis_trigger.go
│ │ │ ├── list.go
│ │ │ ├── publish.go
│ │ │ ├── stream_create.go
│ │ │ └── update.go
│ │ ├── nats/
│ │ │ ├── create.go
│ │ │ ├── delete.go
│ │ │ ├── list.go
│ │ │ ├── nats_trigger.go
│ │ │ ├── publish.go
│ │ │ └── update.go
│ │ └── trigger.go
│ └── version/
│ └── version.go
├── docker/
│ ├── controller-manager
│ ├── dev-environment/
│ │ ├── Dockerfile
│ │ └── entry-point.sh
│ ├── event-sources/
│ │ └── kubernetes/
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ └── events.py
│ ├── function-controller/
│ │ └── Dockerfile
│ ├── function-image-builder/
│ │ ├── Dockerfile
│ │ └── entrypoint.sh
│ ├── runtime/
│ │ └── README.md
│ └── unzip/
│ └── Dockerfile
├── docs/
│ ├── GKE-deployment.md
│ ├── README.md
│ ├── advanced-function-deployment.md
│ ├── architecture.md
│ ├── autoscaling.md
│ ├── building-functions.md
│ ├── cronjob-triggers.md
│ ├── debug-functions.md
│ ├── debugging.md
│ ├── dev-guide.md
│ ├── function-controller-configuration.md
│ ├── http-triggers.md
│ ├── implementing-new-runtime.md
│ ├── implementing-new-trigger.md
│ ├── kubeless-functions.md
│ ├── kubeless-on-AKS.md
│ ├── misc/
│ │ ├── kafka-pv-gke.yaml
│ │ ├── kubeless-grafana-dashboard.json
│ │ └── zookeeper-pv-gke.yaml
│ ├── monitoring.md
│ ├── proposals/
│ │ ├── decoupling-triggers-and-runtimes.md
│ │ └── http-triggers.md
│ ├── pubsub-functions.md
│ ├── quick-start.md
│ ├── release-flow.md
│ ├── runtimes.md
│ ├── streaming-functions.md
│ ├── triggers.md
│ ├── troubleshooting.md
│ └── use-existing-kafka.md
├── examples/
│ ├── Makefile
│ ├── README.md
│ ├── ballerina/
│ │ ├── hello_with_conf/
│ │ │ ├── hello_with_conf.bal
│ │ │ └── kubeless.toml
│ │ ├── helloget.bal
│ │ └── hellowithdata.bal
│ ├── dotnetcore/
│ │ ├── dependency-yaml.cs
│ │ ├── dependency-yaml.csproj
│ │ ├── fibonacci.cs
│ │ ├── fibonacci.csproj
│ │ ├── helloget.cs
│ │ ├── helloget.csproj
│ │ ├── hellowithdata.cs
│ │ └── hellowithdata.csproj
│ ├── golang/
│ │ ├── go.mod
│ │ ├── helloget.go
│ │ ├── hellowithdata.go
│ │ └── hellowithdeps.go
│ ├── java/
│ │ ├── HelloGet.java
│ │ ├── HelloWithData.java
│ │ ├── HelloWithDeps.java
│ │ └── pom.xml
│ ├── jvm/
│ │ ├── Readme.md
│ │ ├── java/
│ │ │ ├── Readme.md
│ │ │ ├── build/
│ │ │ │ └── libs/
│ │ │ │ └── java-0.1-all.jar
│ │ │ ├── build.gradle
│ │ │ ├── src/
│ │ │ │ └── main/
│ │ │ │ └── java/
│ │ │ │ └── io/
│ │ │ │ └── ino/
│ │ │ │ └── Handler.java
│ │ │ └── test-java-jvm.jar
│ │ └── scala/
│ │ ├── Readme.md
│ │ ├── build.sbt
│ │ ├── project/
│ │ │ ├── assembly.sbt
│ │ │ └── build.properties
│ │ └── src/
│ │ └── main/
│ │ └── scala/
│ │ └── de/
│ │ └── inoio/
│ │ └── Handler.scala
│ ├── nodejs/
│ │ ├── function.yaml
│ │ ├── function1.yaml
│ │ ├── helloFunctions.tar.bz2
│ │ ├── helloFunctions.tar.xz
│ │ ├── helloget.js
│ │ ├── hellostream.js
│ │ ├── hellowithdata.js
│ │ ├── hellowithdeps.js
│ │ ├── index.js
│ │ └── package.json
│ ├── php/
│ │ ├── composer.json
│ │ ├── helloget.php
│ │ ├── hellowithdata.php
│ │ └── hellowithdeps.php
│ ├── python/
│ │ ├── Dockerfile
│ │ ├── function.yaml
│ │ ├── function1.yaml
│ │ ├── helloget.py
│ │ ├── hellowithdata.py
│ │ ├── hellowithdeps.py
│ │ ├── hellowithdepshelper.py
│ │ └── requirements.txt
│ └── ruby/
│ ├── Gemfile
│ ├── function.yaml
│ ├── helloget.rb
│ ├── hellowithdata.rb
│ ├── hellowithdeps.rb
│ └── latest.rb
├── go.mod
├── go.sum
├── hack/
│ ├── boilerplate.go.txt
│ └── update-codegen.sh
├── kubeless-non-rbac.jsonnet
├── kubeless-openshift.jsonnet
├── kubeless.jsonnet
├── manifests/
│ ├── README.md
│ ├── autoscaling/
│ │ ├── custom-metrics.yaml
│ │ ├── prometheus-operator.yaml
│ │ ├── sample-metrics-app.yaml
│ │ └── sample-prometheus-instance.yaml
│ ├── kinesis/
│ │ └── kinesalite.yaml
│ ├── monitoring/
│ │ ├── grafana-configmap.yaml
│ │ ├── grafana-deployment.yaml
│ │ ├── grafana-job.yaml
│ │ ├── grafana-service.yaml
│ │ └── prometheus.yaml
│ ├── nats/
│ │ └── nats-cluster.yaml
│ └── ui/
│ └── README.md
├── pkg/
│ ├── apis/
│ │ └── kubeless/
│ │ ├── register.go
│ │ └── v1beta1/
│ │ ├── doc.go
│ │ ├── function.go
│ │ ├── register.go
│ │ └── zz_generated.deepcopy.go
│ ├── client/
│ │ ├── clientset/
│ │ │ └── versioned/
│ │ │ ├── clientset.go
│ │ │ ├── doc.go
│ │ │ ├── fake/
│ │ │ │ ├── clientset_generated.go
│ │ │ │ ├── doc.go
│ │ │ │ └── register.go
│ │ │ ├── scheme/
│ │ │ │ ├── doc.go
│ │ │ │ └── register.go
│ │ │ └── typed/
│ │ │ └── kubeless/
│ │ │ └── v1beta1/
│ │ │ ├── doc.go
│ │ │ ├── fake/
│ │ │ │ ├── doc.go
│ │ │ │ ├── fake_function.go
│ │ │ │ └── fake_kubeless_client.go
│ │ │ ├── function.go
│ │ │ ├── generated_expansion.go
│ │ │ └── kubeless_client.go
│ │ ├── informers/
│ │ │ └── externalversions/
│ │ │ ├── factory.go
│ │ │ ├── generic.go
│ │ │ ├── internalinterfaces/
│ │ │ │ └── factory_interfaces.go
│ │ │ └── kubeless/
│ │ │ ├── interface.go
│ │ │ └── v1beta1/
│ │ │ ├── function.go
│ │ │ └── interface.go
│ │ └── listers/
│ │ └── kubeless/
│ │ └── v1beta1/
│ │ ├── expansion_generated.go
│ │ └── function.go
│ ├── controller/
│ │ ├── function_controller.go
│ │ └── function_controller_test.go
│ ├── function-image-builder/
│ │ ├── image_builder.go
│ │ └── layer-builder/
│ │ ├── description.go
│ │ ├── description_test.go
│ │ ├── layer.go
│ │ ├── layer_builder.go
│ │ ├── layer_test.go
│ │ ├── manifest.go
│ │ └── manifest_test.go
│ ├── function-proxy/
│ │ ├── Gopkg.toml
│ │ ├── proxy.go
│ │ └── utils/
│ │ └── proxy-utils.go
│ ├── functions/
│ │ └── params.go
│ ├── langruntime/
│ │ ├── langruntime.go
│ │ ├── langruntime_test.go
│ │ └── langruntimetestutils.go
│ ├── registry/
│ │ ├── registry.go
│ │ └── registry_test.go
│ ├── utils/
│ │ ├── configlocation.go
│ │ ├── exec.go
│ │ ├── exec_test.go
│ │ ├── k8sutil.go
│ │ ├── k8sutil_test.go
│ │ ├── kubelessutil.go
│ │ ├── kubelessutil_test.go
│ │ └── metrics.go
│ └── version/
│ └── version.go
├── script/
│ ├── .validate
│ ├── binary
│ ├── binary-cli
│ ├── binary-controller
│ ├── cluster-up-minikube.sh
│ ├── create_release.sh
│ ├── enable-gcloud.sh
│ ├── find_digest.sh
│ ├── integration-tests
│ ├── libtest.bash
│ ├── pull-or-build-image.sh
│ ├── release_utils.sh
│ ├── start-gke-env.sh
│ ├── start-test-environment.sh
│ ├── upload_release_notes.sh
│ ├── validate-git-marks
│ ├── validate-gofmt
│ ├── validate-lint
│ ├── validate-test
│ └── validate-vet
└── tests/
├── deployment-tests.bats
├── integration-tests-cronjob.bats
├── integration-tests-http.bats
├── integration-tests-kafka.bats
├── integration-tests-kinesis.bats
├── integration-tests-nats.bats
├── integration-tests-prebuilt.bats
└── integration-tests.bats
================================================
FILE CONTENTS
================================================
================================================
FILE: .circleci/config.yml
================================================
version: 2
## Definitions
build_allways: &build_allways
filters:
tags:
only: /.*/
defaults: &defaults
environment:
CONTROLLER_IMAGE_NAME: kubeless/function-controller
BUILDER_IMAGE_NAME: kubeless/function-image-builder
CGO_ENABLED: "0"
TEST_DEBUG: "1"
GKE_VERSION: 1.12
MINIKUBE_VERSION: v1.2.0
MANIFESTS: kubeless kubeless-non-rbac kubeless-openshift
exports: &exports
# It is not possible to resolve env vars in the environment section:
# https://discuss.circleci.com/t/using-environment-variables-in-config-yml-not-working/14237
run: |
CONTROLLER_TAG=${CIRCLE_TAG:-build-$CIRCLE_WORKFLOW_ID}
echo "export CONTROLLER_TAG=${CONTROLLER_TAG}" >> $BASH_ENV
echo "export CONTROLLER_IMAGE=${CONTROLLER_IMAGE_NAME}:${CONTROLLER_TAG}" >> $BASH_ENV
echo "export FUNCTION_IMAGE_BUILDER=${BUILDER_IMAGE_NAME}:${CONTROLLER_TAG}" >> $BASH_ENV
echo "export KUBECFG_JPATH=/home/circleci/src/github.com/kubeless/kubeless/ksonnet-lib" >> $BASH_ENV
echo "export PATH=$(pwd)/bats/libexec:$GOPATH/bin:$PATH" >> $BASH_ENV
echo "export GIT_SHA1=${CIRCLE_SHA1}" >> $BASH_ENV
restore_workspace: &restore_workspace
run: |
make bootstrap
sudo cp -r /tmp/go/bin/* /usr/local/bin/
cp -r /tmp/go/*yaml .
#### End of definitions
workflows:
version: 2
kubeless:
jobs:
- build:
<<: *build_allways
- minikube:
<<: *build_allways
requires:
- build
- build-cross-binaries:
<<: *build_allways
requires:
- build
- minikube_build_functions:
<<: *build_allways
requires:
- build
- GKE:
<<: *build_allways
requires:
- build
- push_latest_images:
filters:
branches:
only: master
requires:
- minikube
- minikube_build_functions
- GKE
- release:
filters:
tags:
only: /v.*/
branches:
ignore: /.*/
requires:
- minikube
- minikube_build_functions
- GKE
jobs:
build:
<<: *defaults
docker:
- image: circleci/golang:1.15
steps:
- checkout
- restore_cache:
keys:
- go-mod-v4-{{ checksum "go.sum" }}
- <<: *exports
- run: go mod download
- run: make bootstrap
- run: make VERSION=${CONTROLLER_TAG} binary
- run: make test
- run: make validation
- run: make all-yaml
- run: |
mkdir build-manifests
IFS=' ' read -r -a manifests <<< "$MANIFESTS"
for f in "${manifests[@]}"; do
sed -i.bak 's/:latest/'":${CONTROLLER_TAG}"'/g' ${f}.yaml
cp ${f}.yaml build-manifests/
done
- persist_to_workspace:
root: /go
paths:
- ./bin
- persist_to_workspace:
root: ./
paths:
- ./*yaml
- store_artifacts:
path: /go/bin/kubeless
destination: ./bin/kubeless
- store_artifacts:
path: ./build-manifests/
- save_cache:
key: go-mod-v4-{{ checksum "go.sum" }}
paths:
- /go/pkg/mod
minikube:
<<: *defaults
machine:
image: ubuntu-1604:202007-01
steps:
- checkout
- run: sudo apt-get update -y
- run: sudo apt-get install -y tar gzip bzip2 xz-utils
- attach_workspace:
at: /tmp/go
- <<: *exports
- <<: *restore_workspace
- run: ./script/pull-or-build-image.sh function-controller
- run: ./script/integration-tests minikube deployment
- run: ./script/integration-tests minikube basic
build-cross-binaries:
<<: *defaults
docker:
- image: circleci/golang:1.15
steps:
- <<: *exports
- checkout
- attach_workspace:
at: /tmp/go
- <<: *restore_workspace
- run: make VERSION=${CIRCLE_TAG} binary-cross
- store_artifacts:
path: bundles
minikube_build_functions:
<<: *defaults
machine:
image: ubuntu-1604:202007-01
steps:
- checkout
- <<: *exports
- attach_workspace:
at: /tmp/go
- <<: *restore_workspace
- run: ./script/pull-or-build-image.sh function-controller
- run: ./script/pull-or-build-image.sh function-image-builder
- run: "echo '{\"insecure-registries\" : [\"0.0.0.0/0\"]}' > /tmp/daemon.json"
- run: sudo mv /tmp/daemon.json /etc/docker/daemon.json
- run: sudo service docker restart
- run: docker info
- run: docker run -d -p 5000:5000 --restart=always --name registry -v /data/docker-registry:/var/lib/registry registry:2
- run: "sed -i.bak 's/enable-build-step: \"false\"/enable-build-step: \"true\"/g' kubeless.yaml"
- run: "sed -i.bak 's/function-registry-tls-verify: \"true\"/function-registry-tls-verify: \"false\"/g' kubeless.yaml"
- run: ./script/integration-tests minikube deployment
- run: ./script/integration-tests minikube prebuilt_functions
GKE:
<<: *defaults
docker:
- image: circleci/golang:1.15
steps:
- run: |
# In case of GKE we will only want to build if it is
# a build of a branch in the kubeless/kubeless repository
if [[ -n "$GKE_ADMIN" && -z "$CIRCLE_PULL_REQUESTS" ]]; then
export SHOULD_TEST=1
fi
if [[ "$SHOULD_TEST" != "1" ]]; then
circleci step halt
fi
- checkout
- <<: *exports
- attach_workspace:
at: /tmp/go
- <<: *restore_workspace
- setup_remote_docker
- run: ./script/enable-gcloud.sh $(pwd) > /dev/null
- run: echo "export ESCAPED_GKE_CLUSTER=$(echo ${GKE_CLUSTER}-ci-${CIRCLE_BRANCH:-$CIRCLE_TAG} | sed 's/[^a-z0-9-]//g')" >> $BASH_ENV
- run: ./script/start-gke-env.sh $ESCAPED_GKE_CLUSTER $ZONE $GKE_VERSION $GKE_ADMIN > /dev/null
- run: ./script/pull-or-build-image.sh function-controller
- run: ./script/integration-tests gke_${GKE_PROJECT}_${ZONE}_${ESCAPED_GKE_CLUSTER} deployment
- run: ./script/integration-tests gke_${GKE_PROJECT}_${ZONE}_${ESCAPED_GKE_CLUSTER} basic
- run: ./script/integration-tests gke_${GKE_PROJECT}_${ZONE}_${ESCAPED_GKE_CLUSTER} cronjob
push_latest_images:
<<: *defaults
docker:
- image: circleci/golang:1.15
steps:
- <<: *exports
- setup_remote_docker
- run: docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"
- run: |
images=(
$CONTROLLER_IMAGE_NAME
$BUILDER_IMAGE_NAME
)
for image in "${images[@]}"; do
echo "Pulling ${image}:${CONTROLLER_TAG}"
docker pull ${image}:${CONTROLLER_TAG}
docker tag ${image}:${CONTROLLER_TAG} ${image}:latest
docker push ${image}:latest
done
release:
<<: *defaults
docker:
- image: circleci/golang:1.15
steps:
- <<: *exports
- checkout
- attach_workspace:
at: /tmp/go
- <<: *restore_workspace
- run: make VERSION=${CIRCLE_TAG} binary-cross
- run: for d in bundles/kubeless_*; do zip -r9 $d.zip $d/; done
- run: ./script/create_release.sh ${CIRCLE_TAG} "${MANIFESTS}"
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
**Issue Ref**: [Issue number related to this PR or None]
**Description**:
[PR Description]
**TODOs**:
- [ ] Ready to review
- [ ] Automated Tests
- [ ] Docs
================================================
FILE: .github/issue_template.md
================================================
**Is this a BUG REPORT or FEATURE REQUEST?**:
**What happened**:
**What you expected to happen**:
**How to reproduce it (as minimally and precisely as possible)**:
**Anything else we need to know?**:
**Environment**:
- Kubernetes version (use `kubectl version`):
- Kubeless version (use `kubeless version`):
- Cloud provider or physical cluster:
================================================
FILE: .gitignore
================================================
### Go ###
# Binaries for programs and plugins
*.exe
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### OSX ###
*.DS_Store
.AppleDouble
.LSOverride
### vscode ###
.vscode/
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Vim ###
# swap
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-v][a-z]
[._]sw[a-p]
# session
Session.vim
# temporary
.netrwhist
# auto-generated tag files
tags
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# JVM
.classpath
.project
.settings
# Visual Studio 2015 cache/options directory
.vs/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# IDEA Files
.idea/
*.iml
*.ipr
*.iws
# Kubeless specific
bats/
bundles/
docker/function-controller/kubeless-function-controller
docker/function-image-builder/imbuilder
ksonnet-lib/
kubeless-openshift.yaml
kubeless-non-rbac.yaml
kubeless.yaml
kafka-zookeeper.yaml
kafka-zookeeper-openshift.yaml
nats.yaml
kinesis.yaml
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at kubernetes@bitnami.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing Guidelines
## License and CLA
The Kubeless license is Apache Software License V2
We do not currently ask for a Contributor License Agreement to be signed.
## Support Channels
Whether you are a user or contributor, official support channels include:
- GitHub [issues](https://github.com/kubeless/kubeless/issues/new)
- Slack: #kubeless room in the [Kubernetes Slack](http://slack.k8s.io/)
Before opening a new issue or submitting a new pull request, it's helpful to search the project - it's likely that another user has already reported the issue you're facing, or it's a known issue that we're already aware of.
## How to become a contributor and submit your own code
### Setup your development environment
Consult the [Developer's guide](./docs/dev-guide.md) to setup yourself up.
### Contributing a patch
1. Submit an issue describing your proposed change to the repo in question.
2. The [repo owners](OWNERS) will respond to your issue promptly.
3. If your proposed change is accepted, fork the desired repo, develop and test your code changes.
4. Submit a pull request making sure you fill up clearly the description, point out the particular
issue your PR is mitigating, and ask for code review. If the PR is related to Kafka, include at least the tag [Kafka] in the title. You will be asked to add tests (either unit or e2e tests depending on the patch) and update any affected documentation.
## Issues
Issues are used as the primary method for tracking anything to do with the Kubeless project.
### Issue Type
* Question: These are support or functionality inquiries that we want to have a record of for future reference. Generally these are questions that are too complex or large to store in the Slack channel or have particular interest to the community as a whole. Depending on the discussion, these can turn into "Feature" or "Bug" issues.
* Proposal: Used for items (like this one) that propose a new ideas or functionality that require a larger community discussion. This allows for feedback from others in the community before a feature is actually developed. This is not needed for small additions. Final word on whether or not a feature needs a proposal is up to the core maintainers. All issues that are proposals should both have a label and an issue title of "Proposal: [the rest of the title]." A proposal can become a "Feature" and does not require a milestone.
* Features: These track specific feature requests and ideas until they are complete. They can evolve from a "Proposal" or can be submitted individually depending on the size.
* Bugs: These track bugs with the code or problems with the documentation (i.e. missing or incomplete)
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: Makefile
================================================
GO = go
GO_FLAGS =
GOFMT = gofmt
KUBECFG = kubecfg
DOCKER = docker
CONTROLLER_IMAGE = kubeless-function-controller:latest
FUNCTION_IMAGE_BUILDER = kubeless-function-image-builder:latest
OS = linux
ARCH = amd64
BUNDLES = bundles
GO_PACKAGES = ./cmd/... ./pkg/...
GO_FILES := $(shell find $(shell $(GO) list -f '{{.Dir}}' $(GO_PACKAGES)) -name \*.go)
export KUBECFG_JPATH := $(CURDIR)/ksonnet-lib
export PATH := $(PATH):$(CURDIR)/bats/bin
.PHONY: all
KUBELESS_ENVS := \
-e OS_PLATFORM_ARG \
-e OS_ARCH_ARG \
default: binary
binary:
CGO_ENABLED=0 ./script/binary
binary-cross:
./script/binary-cli
%.yaml: %.jsonnet
$(KUBECFG) show -U https://raw.githubusercontent.com/kubeless/runtimes/master -o yaml $< > $@.tmp
mv $@.tmp $@
all-yaml: kubeless.yaml kubeless-non-rbac.yaml kubeless-openshift.yaml
kubeless.yaml: kubeless.jsonnet kubeless-non-rbac.jsonnet
kubeless-non-rbac.yaml: kubeless-non-rbac.jsonnet
kubeless-openshift.yaml: kubeless-openshift.jsonnet
docker/function-controller: controller-build
cp $(BUNDLES)/kubeless_$(OS)-$(ARCH)/kubeless-function-controller $@
controller-build:
./script/binary-controller -os=$(OS) -arch=$(ARCH)
function-controller: docker/function-controller
$(DOCKER) build -t $(CONTROLLER_IMAGE) $<
docker/function-image-builder: function-image-builder-build
cp $(BUNDLES)/kubeless_$(OS)-$(ARCH)/imbuilder $@
function-image-builder-build:
./script/binary-controller -os=$(OS) -arch=$(ARCH) imbuilder github.com/kubeless/kubeless/pkg/function-image-builder
function-image-builder: docker/function-image-builder
$(DOCKER) build -t $(FUNCTION_IMAGE_BUILDER) $<
update:
./hack/update-codegen.sh
test:
$(GO) test $(GO_FLAGS) $(GO_PACKAGES)
validation:
./script/validate-lint
./script/validate-gofmt
./script/validate-git-marks
integration-tests:
./script/integration-tests minikube deployment
./script/integration-tests minikube basic
fmt:
$(GOFMT) -s -w $(GO_FILES)
bats:
git clone --branch=v0.4.0 --depth=1 https://github.com/sstephenson/bats.git
ksonnet-lib:
git clone --depth=1 https://github.com/ksonnet/ksonnet-lib.git
.PHONY: bootstrap
bootstrap: bats ksonnet-lib
GO111MODULE="off" go get -u github.com/mitchellh/gox
GO111MODULE="off" go get -u golang.org/x/lint/golint
@if ! which kubecfg >/dev/null; then \
sudo wget -q -O /usr/local/bin/kubecfg https://github.com/ksonnet/kubecfg/releases/download/v0.9.0/kubecfg-$$(go env GOOS)-$$(go env GOARCH); \
sudo chmod +x /usr/local/bin/kubecfg; \
fi
@if ! which kubectl >/dev/null; then \
KUBECTL_VERSION=$$(wget -qO- https://storage.googleapis.com/kubernetes-release/release/stable.txt); \
sudo wget -q -O /usr/local/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/$$KUBECTL_VERSION/bin/$$(go env GOOS)/$$(go env GOARCH)/kubectl; \
sudo chmod +x /usr/local/bin/kubectl; \
fi
================================================
FILE: OWNERS
================================================
Kubeless - A Bitnami Project
Engineering manager:
- ppbaena
Emeritus maintainers:
- ngtuna
- andresmgot
- anguslees
- sebgoa
================================================
FILE: README.md
================================================
# <img src="https://cloud.githubusercontent.com/assets/4056725/25480209/1d5bf83c-2b48-11e7-8db8-bcd650f31297.png" alt="Kubeless logo" width="400">
[](https://circleci.com/gh/kubeless/kubeless)
[](http://slack.k8s.io)
[](https://gist.github.com/cheerfulstoic/d107229326a01ff0f333a1d3476e068d)
## WARNING: Kubeless is no longer actively maintained by VMware.
VMware has made the difficult decision to stop driving this project and therefore we will no longer actively respond to issues or pull requests. If you would like to take over maintaining this project independently from VMware, please let us know so we can add a link to your forked project here.
Thank You.
## Overview
`kubeless` is a Kubernetes-native serverless framework that lets you deploy small bits of code without having to worry about the underlying infrastructure plumbing. It leverages Kubernetes resources to provide auto-scaling, API routing, monitoring, troubleshooting and more.
Kubeless stands out as we use a [Custom Resource Definition](https://kubernetes.io/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/) to be able to create functions as custom kubernetes resources. We then run an in-cluster controller that watches these custom resources and launches _runtimes_ on-demand. The controller dynamically injects the functions code into the runtimes and make them available over HTTP or via a PubSub mechanism.
Kubeless is purely open-source and non-affiliated to any commercial organization. Chime in at anytime, we would love the help and feedback !
## Tools
- A [UI](https://github.com/kubeless/kubeless-ui) is available. It can run locally or in-cluster.
- A [serverless framework plugin](https://github.com/serverless/serverless-kubeless) is available.
## Quick start
Check out the instructions for quickly set up Kubeless [here](http://kubeless.io/docs/quick-start).
## Building
Consult the [developer's guide](docs/dev-guide.md) for a complete set of instruction
to build kubeless.
## Compatibility Matrix with Kubernetes
Kubeless fully supports Kubernetes versions greater than 1.9 (tested until 1.15). For other versions some of the features in Kubeless may not be available. Our CI run tests against two different platforms: GKE (1.12) and Minikube (1.15). Other platforms are supported but fully compatibiliy cannot be assured.
## _Roadmap_
We would love to get your help, feel free to lend a hand. We are currently looking to implement the following high level features:
- Add other runtimes, currently Golang, Python, NodeJS, Ruby, PHP, .NET and Ballerina are supported. We are also providing a way to use custom runtime. Please check [this doc](./docs/runtimes.md) for more details.
- Investigate other messaging bus (e.g SQS, rabbitMQ)
- Optimize for functions startup time
- Add distributed tracing (maybe using istio)
## Community
**Issues**: If you find any issues, please [file it](https://github.com/kubeless/kubeless/issues).
**Slack**: We're fairly active on [slack](http://slack.k8s.io) and you can find us in the #kubeless channel.
================================================
FILE: cmd/function-controller/function-controller.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Kubeless controller binary.
//
// See github.com/kubeless/kubeless/tree/master/pkg/controller
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
monitoringv1alpha1 "github.com/coreos/prometheus-operator/pkg/client/monitoring/v1alpha1"
"github.com/kubeless/kubeless/pkg/controller"
"github.com/kubeless/kubeless/pkg/utils"
"github.com/kubeless/kubeless/pkg/version"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
const (
globalUsage = `` //TODO: adding explanation
)
var rootCmd = &cobra.Command{
Use: "kubeless-controller",
Short: "Kubeless controller",
Long: globalUsage,
Run: func(cmd *cobra.Command, args []string) {
kubelessClient, err := utils.GetFunctionClientInCluster()
if err != nil {
logrus.Fatalf("Cannot get kubeless client: %v", err)
}
functionCfg := controller.Config{
KubeCli: utils.GetClient(),
FunctionClient: kubelessClient,
}
restCfg, err := utils.GetInClusterConfig()
if err != nil {
logrus.Fatalf("Cannot get REST client: %v", err)
}
// ServiceMonitor client is needed for handling monitoring resources
smclient, err := monitoringv1alpha1.NewForConfig(restCfg)
if err != nil {
logrus.Fatal(err)
}
functionController := controller.NewFunctionController(functionCfg, smclient)
stopCh := make(chan struct{})
defer close(stopCh)
go functionController.Run(stopCh)
sigterm := make(chan os.Signal, 1)
signal.Notify(sigterm, syscall.SIGTERM)
signal.Notify(sigterm, syscall.SIGINT)
<-sigterm
},
}
func main() {
logrus.Infof("Running Kubeless controller manager version: %v", version.Version)
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
================================================
FILE: cmd/kubeless/autoscale/autoscale.go
================================================
/*
Copyright 2016 Skippbox, Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package autoscale
import (
"fmt"
"strconv"
"github.com/spf13/cobra"
"k8s.io/api/autoscaling/v2beta1"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// AutoscaleCmd contains first-class command for autoscale
var AutoscaleCmd = &cobra.Command{
Use: "autoscale SUBCOMMAND",
Short: "manage autoscale to function on Kubeless",
Long: `autoscale command allows user to list, create, delete autoscale rule for function on Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}
func init() {
cmds := []*cobra.Command{autoscaleCreateCmd, autoscaleListCmd, autoscaleDeleteCmd}
for _, cmd := range cmds {
AutoscaleCmd.AddCommand(cmd)
cmd.Flags().StringP("namespace", "n", "", "Specify namespace for the autoscale")
}
}
func getHorizontalAutoscaleDefinition(name, ns, metric string, min, max int32, value string, labels map[string]string) (v2beta1.HorizontalPodAutoscaler, error) {
m := []v2beta1.MetricSpec{}
switch metric {
case "cpu":
i, err := strconv.ParseInt(value, 10, 32)
if err != nil {
return v2beta1.HorizontalPodAutoscaler{}, err
}
i32 := int32(i)
m = []v2beta1.MetricSpec{
{
Type: v2beta1.ResourceMetricSourceType,
Resource: &v2beta1.ResourceMetricSource{
Name: v1.ResourceCPU,
TargetAverageUtilization: &i32,
},
},
}
case "qps":
q, err := resource.ParseQuantity(value)
if err != nil {
return v2beta1.HorizontalPodAutoscaler{}, err
}
m = []v2beta1.MetricSpec{
{
Type: v2beta1.ObjectMetricSourceType,
Object: &v2beta1.ObjectMetricSource{
MetricName: "function_calls",
TargetValue: q,
Target: v2beta1.CrossVersionObjectReference{
Kind: "Service",
Name: name,
},
},
},
}
if err != nil {
return v2beta1.HorizontalPodAutoscaler{}, err
}
default:
return v2beta1.HorizontalPodAutoscaler{}, fmt.Errorf("metric %s is not supported", metric)
}
return v2beta1.HorizontalPodAutoscaler{
TypeMeta: metav1.TypeMeta{
APIVersion: "autoscaling/v2beta1",
Kind: "HorizontalPodAutoscaler",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: ns,
Labels: labels,
},
Spec: v2beta1.HorizontalPodAutoscalerSpec{
ScaleTargetRef: v2beta1.CrossVersionObjectReference{
APIVersion: "apps/v1beta1",
Kind: "Deployment",
Name: name,
},
MinReplicas: &min,
MaxReplicas: max,
Metrics: m,
},
}, nil
}
================================================
FILE: cmd/kubeless/autoscale/autoscaleCreate.go
================================================
package autoscale
import (
"github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
var autoscaleCreateCmd = &cobra.Command{
Use: "create <name> FLAG",
Short: "automatically scale function based on monitored metrics",
Long: `automatically scale function based on monitored metrics`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - function name")
}
funcName := args[0]
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
if ns == "" {
ns = utils.GetDefaultNamespace()
}
function, err := utils.GetFunction(funcName, ns)
if err != nil {
logrus.Fatalf("Unable to find the function %s. Received %s: ", funcName, err)
}
min, err := cmd.Flags().GetInt32("min")
if err != nil {
logrus.Fatal(err)
} else if min <= 0 {
logrus.Fatalf("min can't be negative or zero")
}
max, err := cmd.Flags().GetInt32("max")
if err != nil {
logrus.Fatal(err)
} else if max < min {
logrus.Fatalf("max must be greater than or equal to min")
}
metric, err := cmd.Flags().GetString("metric")
if err != nil {
logrus.Fatal(err)
}
if metric != "cpu" && metric != "qps" {
logrus.Fatalf("only supported metrics: cpu, qps")
}
value, err := cmd.Flags().GetString("value")
if err != nil {
logrus.Fatal(err)
}
hpa, err := getHorizontalAutoscaleDefinition(funcName, ns, metric, min, max, value, function.ObjectMeta.Labels)
if err != nil {
logrus.Fatal(err)
}
function.Spec.HorizontalPodAutoscaler = hpa
kubelessClient, err := utils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatal(err)
}
logrus.Infof("Adding autoscaling rule to the function...")
err = utils.UpdateFunctionCustomResource(kubelessClient, &function)
if err != nil {
logrus.Fatal(err)
}
logrus.Infof("Autoscaling rule for %s submitted for deployment", funcName)
},
}
func init() {
autoscaleCreateCmd.Flags().Int32("min", 1, "minimum number of replicas")
autoscaleCreateCmd.Flags().Int32("max", 1, "maximum number of replicas")
autoscaleCreateCmd.Flags().String("metric", "cpu", "metric to use for calculating the autoscale. Supported metrics: cpu, qps")
autoscaleCreateCmd.Flags().String("value", "", "value of the average of the metric across all replicas. If metric is cpu, value is a number represented as percentage. If metric is qps, value must be in format of Quantity")
autoscaleCreateCmd.MarkFlagRequired("value")
}
================================================
FILE: cmd/kubeless/autoscale/autoscaleDelete.go
================================================
/*
Copyright 2016 Skippbox, Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package autoscale
import (
"github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"k8s.io/api/autoscaling/v2beta1"
)
var autoscaleDeleteCmd = &cobra.Command{
Use: "delete <name>",
Short: "delete an autoscale from Kubeless",
Long: `delete an autoscale from Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - autoscale name")
}
funcName := args[0]
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
if ns == "" {
ns = utils.GetDefaultNamespace()
}
function, err := utils.GetFunction(funcName, ns)
if err != nil {
logrus.Fatalf("Unable to find the function %s. Received %s: ", funcName, err)
}
if function.Spec.HorizontalPodAutoscaler.Name != "" {
function.Spec.HorizontalPodAutoscaler = v2beta1.HorizontalPodAutoscaler{}
kubelessClient, err := utils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatal(err)
}
logrus.Infof("Removing autoscaling rule from the function...")
err = utils.UpdateFunctionCustomResource(kubelessClient, &function)
if err != nil {
logrus.Fatal(err)
}
logrus.Infof("Remove Autoscaling rule from %s successfully", funcName)
} else {
logrus.Fatalf("Not found an autoscale definition for %s", funcName)
}
},
}
================================================
FILE: cmd/kubeless/autoscale/autoscaleList.go
================================================
/*
Copyright 2016 Skippbox, Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package autoscale
import (
"encoding/json"
"fmt"
"io"
"github.com/ghodss/yaml"
"github.com/gosuri/uitable"
"github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"k8s.io/api/autoscaling/v2beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
var autoscaleListCmd = &cobra.Command{
Use: "list FLAG",
Aliases: []string{"ls"},
Short: "list all autoscales in Kubeless",
Long: `list all autoscales in Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
output, err := cmd.Flags().GetString("out")
if err != nil {
logrus.Fatal(err.Error())
}
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err.Error())
}
if ns == "" {
ns = utils.GetDefaultNamespace()
}
client := utils.GetClientOutOfCluster()
if err := doAutoscaleList(cmd.OutOrStdout(), client, ns, output); err != nil {
logrus.Fatal(err.Error())
}
},
}
func init() {
autoscaleListCmd.Flags().StringP("out", "o", "", "Output format. One of: json|yaml")
}
func doAutoscaleList(w io.Writer, client kubernetes.Interface, ns, output string) error {
asList, err := client.AutoscalingV2beta1().HorizontalPodAutoscalers(ns).List(metav1.ListOptions{
LabelSelector: "created-by=kubeless",
})
if err != nil {
return err
}
return printAutoscale(w, asList.Items, output)
}
// printAutoscale formats the output of autoscale list
func printAutoscale(w io.Writer, ass []v2beta1.HorizontalPodAutoscaler, output string) error {
if output == "" {
table := uitable.New()
table.MaxColWidth = 50
table.Wrap = true
table.AddRow("NAME", "NAMESPACE", "TARGET", "MIN", "MAX", "METRIC", "VALUE")
for _, i := range ass {
n := i.Name
ns := i.Namespace
ta := i.Spec.ScaleTargetRef.Name
min := i.Spec.MinReplicas
max := i.Spec.MaxReplicas
m := ""
v := ""
if len(i.Spec.Metrics) == 0 {
logrus.Errorf("The autoscale %s has bad format. It has no metric defined.", i.Name)
continue
}
if i.Spec.Metrics[0].Object != nil {
m = i.Spec.Metrics[0].Object.MetricName
v = i.Spec.Metrics[0].Object.TargetValue.String()
} else if i.Spec.Metrics[0].Resource != nil {
m = string(i.Spec.Metrics[0].Resource.Name)
v = fmt.Sprint(*i.Spec.Metrics[0].Resource.TargetAverageUtilization)
}
table.AddRow(n, ns, ta, fmt.Sprint(*min), fmt.Sprint(max), m, v)
}
fmt.Fprintln(w, table)
} else {
for _, i := range ass {
switch output {
case "json":
b, err := json.MarshalIndent(i, "", " ")
if err != nil {
return err
}
fmt.Fprintln(w, string(b))
case "yaml":
b, err := yaml.Marshal(i)
if err != nil {
return err
}
fmt.Fprintln(w, string(b))
default:
return fmt.Errorf("Wrong output format. Only accept json|yaml file")
}
}
}
return nil
}
================================================
FILE: cmd/kubeless/autoscale/autoscaleList_test.go
================================================
package autoscale
import (
"bytes"
"strings"
"testing"
av2alpha1 "k8s.io/api/autoscaling/v2beta1"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"
)
func listAutoscaleOutput(t *testing.T, client kubernetes.Interface, ns, output string) string {
var buf bytes.Buffer
if err := doAutoscaleList(&buf, client, ns, output); err != nil {
t.Fatalf("doList returned error: %v", err)
}
return buf.String()
}
func TestAutoscaleList(t *testing.T) {
replicas := int32(1)
targetAverageUtilization := int32(50)
q, _ := resource.ParseQuantity("10k")
as1 := av2alpha1.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: "myns",
Labels: map[string]string{
"created-by": "kubeless",
},
},
Spec: av2alpha1.HorizontalPodAutoscalerSpec{
ScaleTargetRef: av2alpha1.CrossVersionObjectReference{
Kind: "Deployment",
Name: "foo",
},
MinReplicas: &replicas,
MaxReplicas: replicas,
Metrics: []av2alpha1.MetricSpec{
{
Type: av2alpha1.ResourceMetricSourceType,
Resource: &av2alpha1.ResourceMetricSource{
Name: v1.ResourceCPU,
TargetAverageUtilization: &targetAverageUtilization,
},
},
},
},
}
as2 := av2alpha1.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "bar",
Namespace: "myns",
Labels: map[string]string{
"created-by": "kubeless",
},
},
Spec: av2alpha1.HorizontalPodAutoscalerSpec{
ScaleTargetRef: av2alpha1.CrossVersionObjectReference{
Kind: "Deployment",
Name: "foo",
},
MinReplicas: &replicas,
MaxReplicas: replicas,
Metrics: []av2alpha1.MetricSpec{
{
Type: av2alpha1.ObjectMetricSourceType,
Object: &av2alpha1.ObjectMetricSource{
MetricName: "function_calls",
TargetValue: q,
Target: av2alpha1.CrossVersionObjectReference{
Kind: "Service",
Name: "foo",
},
},
},
},
},
}
as3 := av2alpha1.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "foobar",
Namespace: "myns",
},
}
client := fake.NewSimpleClientset(&as1, &as2, &as3)
output := listAutoscaleOutput(t, client, "myns", "")
t.Log("output is", output)
if !strings.Contains(output, "foo") || !strings.Contains(output, "bar") {
t.Errorf("table output didn't mention both autoscales")
}
if strings.Contains(output, "foobar") {
t.Errorf("table output shouldn't mention foobar autoscale as it isn't created by kubeless")
}
// json output
output = listAutoscaleOutput(t, client, "myns", "json")
t.Log("output is", output)
// yaml output
output = listAutoscaleOutput(t, client, "myns", "yaml")
t.Log("output is", output)
}
================================================
FILE: cmd/kubeless/autoscale/autoscale_test.go
================================================
package autoscale
import (
"reflect"
"testing"
"k8s.io/api/autoscaling/v2beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestGetHorizontalAutoscaleDefinition(t *testing.T) {
var min, max int32
min = 1
max = 3
funcName := "test-autoscale"
ns := "default"
value := "10"
labels := map[string]string{
"foo": "bar",
}
metric := "cpu"
hpa, err := getHorizontalAutoscaleDefinition(funcName, ns, metric, min, max, value, labels)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
expectedMeta := metav1.ObjectMeta{
Name: funcName,
Namespace: ns,
Labels: labels,
}
if hpa.Spec.ScaleTargetRef.Name != funcName {
t.Fatalf("Creating wrong scale target name")
}
if !reflect.DeepEqual(expectedMeta, hpa.ObjectMeta) {
t.Errorf("Expected \n%v to be equal to \n%v", expectedMeta, hpa.ObjectMeta)
}
if *hpa.Spec.MinReplicas != min {
t.Errorf("Unexpected min replicas. Expecting %d got %d", min, *hpa.Spec.MinReplicas)
}
if hpa.Spec.MaxReplicas != max {
t.Errorf("Unexpected max replicas. Expecting %d got %d", max, hpa.Spec.MaxReplicas)
}
if hpa.Spec.Metrics[0].Type != v2beta1.ResourceMetricSourceType ||
*hpa.Spec.Metrics[0].Resource.TargetAverageUtilization != int32(10) {
t.Error("Unexpected metric")
}
metric = "qps"
hpa, err = getHorizontalAutoscaleDefinition(funcName, ns, metric, min, max, value, labels)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if hpa.Spec.Metrics[0].Type != v2beta1.ObjectMetricSourceType ||
hpa.Spec.Metrics[0].Object.TargetValue.String() != "10" {
t.Error("Unexpected metric")
}
}
================================================
FILE: cmd/kubeless/completion/completion.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package completion
import (
"github.com/spf13/cobra"
"os"
)
// CompletionCmd contains first-class command for completion
var CompletionCmd = &cobra.Command{
Use: "completion [bash|zsh|fish|powershell]",
Short: "Generate completion script",
Long: `To load completions:
Bash:
$ source <(kubeless completion bash)
# To load completions for each session, execute once:
Linux:
$ kubeless completion bash > /etc/bash_completion.d/kubeless
MacOS:
$ kubeless completion bash > /usr/local/etc/bash_completion.d/kubeless
Zsh:
# If shell completion is not already enabled in your environment you will need
# to enable it. You can execute the following once:
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
# To load completions for each session, execute once:
$ kubeless completion zsh > "${fpath[1]}/_kubeless"
# You will need to start a new shell for this setup to take effect.
Fish:
$ kubeless completion fish | source
# To load completions for each session, execute once:
$ kubeless completion fish > ~/.config/fish/completions/kubeless.fish
`,
DisableFlagsInUseLine: true,
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
Args: cobra.ExactValidArgs(1),
Run: func(cmd *cobra.Command, args []string) {
switch args[0] {
case "bash":
cmd.Root().GenBashCompletion(os.Stdout)
case "zsh":
cmd.Root().GenZshCompletion(os.Stdout)
case "fish":
cmd.Root().GenFishCompletion(os.Stdout, true)
case "powershell":
cmd.Root().GenPowerShellCompletion(os.Stdout)
}
},
}
================================================
FILE: cmd/kubeless/function/call.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package function
import (
"bytes"
"fmt"
"strconv"
"strings"
"time"
"github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/rest"
)
var callCmd = &cobra.Command{
Use: "call <function_name> FLAG",
Short: "call function from cli",
Long: `call function from cli`,
Run: func(cmd *cobra.Command, args []string) {
var (
str []byte
get bool = false
)
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - function name")
}
funcName := args[0]
data, err := cmd.Flags().GetString("data")
if data == "" {
get = true
} else {
str = []byte(data)
}
if err != nil {
logrus.Fatal(err)
}
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
if ns == "" {
ns = utils.GetDefaultNamespace()
}
clientset := utils.GetClientOutOfCluster()
svc, err := clientset.CoreV1().Services(ns).Get(funcName, metav1.GetOptions{})
if err != nil {
logrus.Fatalf("Unable to find the service for %s", funcName)
}
port := strconv.Itoa(int(svc.Spec.Ports[0].Port))
if svc.Spec.Ports[0].Name != "" {
port = svc.Spec.Ports[0].Name
}
req := &rest.Request{}
if get {
req = clientset.CoreV1().RESTClient().Get().Namespace(ns).Resource("services").SubResource("proxy").Name(funcName + ":" + port)
} else {
req = clientset.CoreV1().RESTClient().Post().Namespace(ns).Resource("services").SubResource("proxy").Name(funcName + ":" + port).Body(bytes.NewBuffer(str))
if utils.IsJSON(string(str)) {
req.SetHeader("Content-Type", "application/json")
req.SetHeader("event-type", "application/json")
} else {
req.SetHeader("Content-Type", "application/x-www-form-urlencoded")
req.SetHeader("event-type", "application/x-www-form-urlencoded")
}
// REST package removes trailing slash when building URLs
// Causing POST requests to be redirected with an empty body
// So we need to manually build the URL
req = req.AbsPath(req.URL().Path + "/")
}
timestamp := time.Now().UTC()
eventID, err := utils.GetRandString(11)
if err != nil {
logrus.Fatalf("Unable to generate ID %v", err)
}
req.SetHeader("event-id", eventID)
req.SetHeader("event-time", timestamp.Format(time.RFC3339))
req.SetHeader("event-namespace", "cli.kubeless.io")
res, err := req.Do().Raw()
if err != nil {
// Properly interpret line breaks
logrus.Error(string(res))
if strings.Contains(err.Error(), "status code 408") {
// Give a more meaninful error for timeout errors
logrus.Fatal("Request timeout exceeded")
} else {
logrus.Fatal(strings.Replace(err.Error(), `\n`, "\n", -1))
}
}
fmt.Println(string(res))
},
}
func init() {
callCmd.Flags().StringP("data", "d", "", "Specify data for function")
callCmd.Flags().StringP("namespace", "n", "", "Specify namespace for the function")
}
================================================
FILE: cmd/kubeless/function/delete.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package function
import (
"github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
var deleteCmd = &cobra.Command{
Use: "delete <function_name>",
Short: "delete a function from Kubeless",
Long: `delete a function from Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - function name")
}
funcName := args[0]
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
if ns == "" {
ns = utils.GetDefaultNamespace()
}
kubelessClient, err := utils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatal(err)
}
err = utils.DeleteFunctionCustomResource(kubelessClient, funcName, ns)
if err != nil {
logrus.Fatal(err)
}
},
}
func init() {
deleteCmd.Flags().StringP("namespace", "n", "", "Specify namespace for the function")
}
================================================
FILE: cmd/kubeless/function/deploy.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package function
import (
"encoding/json"
"fmt"
"strings"
"github.com/ghodss/yaml"
cronjobApi "github.com/kubeless/cronjob-trigger/pkg/apis/kubeless/v1beta1"
cronjobUtils "github.com/kubeless/cronjob-trigger/pkg/utils"
kubelessApi "github.com/kubeless/kubeless/pkg/apis/kubeless/v1beta1"
"github.com/kubeless/kubeless/pkg/langruntime"
kubelessutil "github.com/kubeless/kubeless/pkg/utils"
"github.com/robfig/cron"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var deployCmd = &cobra.Command{
Use: "deploy <function_name> FLAG",
Short: "deploy a function to Kubeless",
Long: `deploy a function to Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
cli := kubelessutil.GetClientOutOfCluster()
apiExtensionsClientset := kubelessutil.GetAPIExtensionsClientOutOfCluster()
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - function name")
}
funcName := args[0]
runtime, err := cmd.Flags().GetString("runtime")
if err != nil {
logrus.Fatal(err)
}
// Checking runtime parameter if allowed by RBAC, otherwide skip the check
config, err := kubelessutil.GetKubelessConfig(cli, apiExtensionsClientset)
if config == nil || err != nil {
logrus.Warnf("%v. Runtime check is disabled.", err)
} else {
lr := langruntime.New(config)
lr.ReadConfigMap()
if runtime != "" && !lr.IsValidRuntime(runtime) {
logrus.Fatalf("Invalid runtime: %s. Supported runtimes are: %s",
runtime, strings.Join(lr.GetRuntimes(), ", "))
}
}
schedule, err := cmd.Flags().GetString("schedule")
if err != nil {
logrus.Fatal(err)
}
if schedule != "" {
if _, err := cron.ParseStandard(schedule); err != nil {
logrus.Fatalf("Invalid value for --schedule. " + err.Error())
}
}
labels, err := cmd.Flags().GetStringSlice("label")
if err != nil {
logrus.Fatal(err)
}
envs, err := cmd.Flags().GetStringSlice("env")
if err != nil {
logrus.Fatal(err)
}
handler, err := cmd.Flags().GetString("handler")
if err != nil {
logrus.Fatal(err)
}
file, err := cmd.Flags().GetString("from-file")
if err != nil {
logrus.Fatal(err)
}
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
var nsArg string
if ns == "" {
ns = kubelessutil.GetDefaultNamespace()
} else {
nsArg = fmt.Sprintf(" -n %s", ns)
}
deps, err := cmd.Flags().GetString("dependencies")
if err != nil {
logrus.Fatal(err)
}
secrets, err := cmd.Flags().GetStringSlice("secrets")
if err != nil {
logrus.Fatal(err)
}
serviceAccount, err := cmd.Flags().GetString("service-account")
if err != nil {
logrus.Fatal(err)
}
runtimeImage, err := cmd.Flags().GetString("runtime-image")
if err != nil {
logrus.Fatal(err)
}
imagePullPolicy, err := cmd.Flags().GetString("image-pull-policy")
if err != nil {
logrus.Fatal(err)
}
if imagePullPolicy != "IfNotPresent" && imagePullPolicy != "Always" && imagePullPolicy != "Never" {
err := fmt.Errorf("image-pull-policy must be {IfNotPresent|Always|Never}")
logrus.Fatal(err)
}
mem, err := cmd.Flags().GetString("memory")
if err != nil {
logrus.Fatal(err)
}
cpu, err := cmd.Flags().GetString("cpu")
if err != nil {
logrus.Fatal(err)
}
timeout, err := cmd.Flags().GetString("timeout")
if err != nil {
logrus.Fatal(err)
}
output, err := cmd.Flags().GetString("output")
if err != nil {
logrus.Fatal(err)
}
headless, err := cmd.Flags().GetBool("headless")
if err != nil {
logrus.Fatal(err)
}
dryrun, err := cmd.Flags().GetBool("dryrun")
if err != nil {
logrus.Fatal(err)
}
port, err := cmd.Flags().GetInt32("port")
if err != nil {
logrus.Fatal(err)
}
if port <= 0 || port > 65535 {
logrus.Fatalf("Invalid port number %d specified", port)
}
servicePort, err := cmd.Flags().GetInt32("servicePort")
if err != nil {
logrus.Fatal(err)
}
if servicePort < 0 || servicePort > 65535 {
logrus.Fatalf("Invalid servicePort number %d specified", servicePort)
}
funcDeps := ""
if deps != "" {
contentType, err := kubelessutil.GetContentType(deps)
if err != nil {
logrus.Fatal(err)
}
funcDeps, _, err = kubelessutil.ParseContent(deps, contentType)
if err != nil {
logrus.Fatal(err)
}
}
if runtime == "" && runtimeImage == "" {
logrus.Fatal("Either `--runtime` or `--runtime-image` flag must be specified.")
}
if runtime != "" && handler == "" {
logrus.Fatal("You must specify handler for the runtime.")
}
nodeSelectors, err := cmd.Flags().GetStringSlice("node-selectors")
if err != nil {
logrus.Fatal(err)
}
defaultFunctionSpec := kubelessApi.Function{}
defaultFunctionSpec.ObjectMeta.Labels = map[string]string{
"created-by": "kubeless",
"function": funcName,
}
f, err := getFunctionDescription(funcName, ns, handler, file, funcDeps, runtime, runtimeImage, mem, cpu, timeout, imagePullPolicy, serviceAccount, port, servicePort, headless, envs, labels, secrets, nodeSelectors, defaultFunctionSpec)
if err != nil {
logrus.Fatal(err)
}
if dryrun == true {
if output == "json" {
j, err := json.MarshalIndent(f, "", " ")
if err != nil {
logrus.Fatal(err)
}
fmt.Println(string(j[:]))
return
} else if output == "yaml" {
y, err := yaml.Marshal(f)
if err != nil {
logrus.Fatal(err)
}
fmt.Println(string(y[:]))
return
} else {
logrus.Infof("Output format needs to be yaml or json")
return
}
}
kubelessClient, err := kubelessutil.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatal(err)
}
logrus.Infof("Deploying function...")
err = kubelessutil.CreateFunctionCustomResource(kubelessClient, f)
if err != nil {
logrus.Fatalf("Failed to deploy %s. Received:\n%s", funcName, err)
}
logrus.Infof("Function %s submitted for deployment", funcName)
logrus.Infof("Check the deployment status executing 'kubeless function ls %s%s'", funcName, nsArg)
if schedule != "" {
cronJobTrigger := cronjobApi.CronJobTrigger{}
cronJobTrigger.TypeMeta = metav1.TypeMeta{
Kind: "CronJobTrigger",
APIVersion: "kubeless.io/v1beta1",
}
cronJobTrigger.ObjectMeta = metav1.ObjectMeta{
Name: funcName,
Namespace: ns,
}
cronJobTrigger.ObjectMeta.Labels = map[string]string{
"created-by": "kubeless",
"function": funcName,
}
cronJobTrigger.Spec.FunctionName = funcName
cronJobTrigger.Spec.Schedule = schedule
cronjobClient, err := cronjobUtils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatal(err)
}
err = cronjobUtils.CreateCronJobCustomResource(cronjobClient, &cronJobTrigger)
if err != nil {
logrus.Fatalf("Failed to deploy cron job trigger %s. Received:\n%s", funcName, err)
}
}
},
}
func init() {
deployCmd.Flags().StringP("runtime", "r", "", "Specify runtime")
deployCmd.Flags().StringP("handler", "", "", "Specify handler")
deployCmd.Flags().StringP("from-file", "f", "", "Specify code file or a URL to the code file")
deployCmd.Flags().StringSliceP("label", "l", []string{}, "Specify labels of the function. Both separator ':' and '=' are allowed. For example: --label foo1=bar1,foo2:bar2")
deployCmd.Flags().StringSliceP("secrets", "", []string{}, "Specify Secrets to be mounted to the functions container. For example: --secrets mySecret")
deployCmd.Flags().StringSliceP("env", "e", []string{}, "Specify environment variable of the function. Both separator ':' and '=' are allowed. For example: --env foo1=bar1,foo2:bar2")
deployCmd.Flags().StringSliceP("node-selectors", "", []string{}, "Specify node selectors for the function. Both separator ':' and '=' are allowed. For example: --node-selectors key1=val1,key2:val2")
deployCmd.Flags().StringP("service-account", "", "", "Specify service account for the function. For example: --service-account controller-acct")
deployCmd.Flags().StringP("namespace", "n", "", "Specify namespace for the function")
deployCmd.Flags().StringP("dependencies", "d", "", "Specify a file containing list of dependencies for the function")
deployCmd.Flags().StringP("schedule", "", "", "Specify schedule in cron format for scheduled function")
deployCmd.Flags().StringP("memory", "", "", "Request amount of memory, which is measured in bytes, for the function. It is expressed as a plain integer or a fixed-point interger with one of these suffies: E, P, T, G, M, K, Ei, Pi, Ti, Gi, Mi, Ki")
deployCmd.Flags().StringP("cpu", "", "", "Request amount of cpu for the function, which is measured in units of cores. Please see the following link for more information: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu")
deployCmd.Flags().StringP("runtime-image", "", "", "Custom runtime image")
deployCmd.Flags().StringP("image-pull-policy", "", "Always", "Image pull policy")
deployCmd.Flags().StringP("timeout", "", "180", "Maximum timeout (in seconds) for the function to complete its execution")
deployCmd.Flags().StringP("output", "o", "yaml", "Output format")
deployCmd.Flags().Bool("headless", false, "Deploy http-based function without a single service IP and load balancing support from Kubernetes. See: https://kubernetes.io/docs/concepts/services-networking/service/#headless-services")
deployCmd.Flags().Bool("dryrun", false, "Output JSON manifest of the function without creating it")
deployCmd.Flags().Int32("port", 8080, "Deploy http-based function with a custom port")
deployCmd.Flags().Int32("servicePort", 0, "Deploy http-based function with a custom service port. If not provided the value of 'port' will be used")
}
================================================
FILE: cmd/kubeless/function/describe.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package function
import (
"encoding/json"
"fmt"
"github.com/ghodss/yaml"
"github.com/gosuri/uitable"
kubelessApi "github.com/kubeless/kubeless/pkg/apis/kubeless/v1beta1"
"github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
var describeCmd = &cobra.Command{
Use: "describe FLAG",
Aliases: []string{"ls"},
Short: "describe a function deployed to Kubeless",
Long: `describe a function deployed to Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - function name")
}
funcName := args[0]
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatalf("Can not describe function: %v", err)
}
if ns == "" {
ns = utils.GetDefaultNamespace()
}
output, err := cmd.Flags().GetString("out")
if err != nil {
logrus.Fatalf("Can not describe function: %v", err)
}
f, err := utils.GetFunction(funcName, ns)
if err != nil {
logrus.Fatalf("Can not describe function: %v", err)
}
err = print(f, funcName, output)
if err != nil {
logrus.Fatalf("Can not describe function: %v", err)
}
},
}
func init() {
describeCmd.Flags().StringP("out", "o", "", "Output format. One of: json|yaml")
describeCmd.Flags().StringP("namespace", "n", "", "Specify namespace for the function")
}
func print(f kubelessApi.Function, name, output string) error {
switch output {
case "":
table := uitable.New()
table.MaxColWidth = 80
table.Wrap = true
label, err := json.Marshal(f.ObjectMeta.Labels)
if err != nil {
return err
}
var env, memory string
if len(f.Spec.Deployment.Spec.Template.Spec.Containers) != 0 {
b, err := json.Marshal(f.Spec.Deployment.Spec.Template.Spec.Containers[0].Env)
if err != nil {
return err
}
env = string(b)
memory = f.Spec.Deployment.Spec.Template.Spec.Containers[0].Resources.Requests.Memory().String()
}
table.AddRow("Name:", name)
table.AddRow("Namespace:", f.ObjectMeta.Namespace)
table.AddRow("Handler:", f.Spec.Handler)
table.AddRow("Runtime:", f.Spec.Runtime)
table.AddRow("Label:", string(label))
table.AddRow("Envvar:", env)
table.AddRow("Memory:", memory)
table.AddRow("Dependencies:", f.Spec.Deps)
fmt.Println(table)
case "json":
b, err := json.MarshalIndent(f, "", " ")
if err != nil {
return err
}
fmt.Println(string(b))
case "yaml":
b, err := yaml.Marshal(f)
if err != nil {
return err
}
fmt.Println(string(b))
default:
fmt.Println("Wrong output format. Please use only json|yaml")
}
return nil
}
================================================
FILE: cmd/kubeless/function/function.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package function
import (
"fmt"
"strings"
kubelessApi "github.com/kubeless/kubeless/pkg/apis/kubeless/v1beta1"
"github.com/kubeless/kubeless/pkg/client/clientset/versioned"
kubelessutil "github.com/kubeless/kubeless/pkg/utils"
"github.com/spf13/cobra"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/kubernetes"
)
// FunctionCmd contains first-class command for function
var FunctionCmd = &cobra.Command{
Use: "function SUBCOMMAND",
Short: "function specific operations",
Long: `function command allows user to list, deploy, edit, delete functions running on Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}
func init() {
FunctionCmd.AddCommand(deployCmd)
FunctionCmd.AddCommand(deleteCmd)
FunctionCmd.AddCommand(listCmd)
FunctionCmd.AddCommand(callCmd)
FunctionCmd.AddCommand(logsCmd)
FunctionCmd.AddCommand(describeCmd)
FunctionCmd.AddCommand(updateCmd)
FunctionCmd.AddCommand(topCmd)
}
func getKV(input string) (string, string) {
var key, value string
if pos := strings.IndexAny(input, "=:"); pos != -1 {
key = input[:pos]
value = input[pos+1:]
} else {
// no separator found
key = input
value = ""
}
return key, value
}
func parseLabel(labels []string) map[string]string {
funcLabels := make(map[string]string)
for _, label := range labels {
k, v := getKV(label)
funcLabels[k] = v
}
return funcLabels
}
func parseEnv(envs []string) []v1.EnvVar {
funcEnv := []v1.EnvVar{}
for _, env := range envs {
k, v := getKV(env)
funcEnv = append(funcEnv, v1.EnvVar{
Name: k,
Value: v,
})
}
return funcEnv
}
func parseResource(in string) (resource.Quantity, error) {
if in == "" {
return resource.Quantity{}, nil
}
quantity, err := resource.ParseQuantity(in)
if err != nil {
return resource.Quantity{}, err
}
return quantity, nil
}
func parseNodeSelectors(nodeSelectors []string) map[string]string {
funcNodeSelectors := make(map[string]string)
for _, nodeSelector := range nodeSelectors {
k, v := getKV(nodeSelector)
funcNodeSelectors[k] = v
}
return funcNodeSelectors
}
func getFunctionDescription(funcName, ns, handler, file, deps, runtime, runtimeImage, mem, cpu, timeout string, imagePullPolicy string, serviceAccount string, port int32, servicePort int32, headless bool, envs, labels, secrets, nodeSelectors []string, defaultFunction kubelessApi.Function) (*kubelessApi.Function, error) {
function := defaultFunction
function.TypeMeta = metav1.TypeMeta{
Kind: "Function",
APIVersion: "kubeless.io/v1beta1",
}
if handler != "" {
function.Spec.Handler = handler
}
if file != "" {
contentType, err := kubelessutil.GetContentType(file)
if err != nil {
return nil, err
}
functionContent, checksum, err := kubelessutil.ParseContent(file, contentType)
if err != nil {
return nil, err
}
if strings.Contains(contentType, "url") {
// set the function to be the URL provided on the command line
function.Spec.Function = file
} else {
function.Spec.Function = functionContent
}
function.Spec.Checksum = checksum
function.Spec.FunctionContentType = contentType
}
if deps != "" {
function.Spec.Deps = deps
}
if runtime != "" {
function.Spec.Runtime = runtime
}
if timeout != "" {
function.Spec.Timeout = timeout
}
funcEnv := parseEnv(envs)
if len(funcEnv) == 0 && len(defaultFunction.Spec.Deployment.Spec.Template.Spec.Containers) != 0 {
funcEnv = defaultFunction.Spec.Deployment.Spec.Template.Spec.Containers[0].Env
}
funcLabels := defaultFunction.ObjectMeta.Labels
if len(funcLabels) == 0 {
funcLabels = make(map[string]string)
}
ls := parseLabel(labels)
for k, v := range ls {
funcLabels[k] = v
}
function.ObjectMeta = metav1.ObjectMeta{
Name: funcName,
Namespace: ns,
Labels: funcLabels,
}
resources := v1.ResourceRequirements{}
if mem != "" || cpu != "" {
funcMem, err := parseResource(mem)
if err != nil {
err = fmt.Errorf("Wrong format of the memory value: %v", err)
return &kubelessApi.Function{}, err
}
funcCPU, err := parseResource(cpu)
if err != nil {
err = fmt.Errorf("Wrong format for cpu value: %v", err)
return &kubelessApi.Function{}, err
}
resource := map[v1.ResourceName]resource.Quantity{
v1.ResourceMemory: funcMem,
v1.ResourceCPU: funcCPU,
}
resources = v1.ResourceRequirements{
Limits: resource,
Requests: resource,
}
} else {
if len(defaultFunction.Spec.Deployment.Spec.Template.Spec.Containers) != 0 {
resources = defaultFunction.Spec.Deployment.Spec.Template.Spec.Containers[0].Resources
}
}
if len(runtimeImage) == 0 && len(defaultFunction.Spec.Deployment.Spec.Template.Spec.Containers) != 0 {
runtimeImage = defaultFunction.Spec.Deployment.Spec.Template.Spec.Containers[0].Image
}
function.Spec.Deployment.Spec.Template.Spec.Containers = []v1.Container{
{
ImagePullPolicy: v1.PullPolicy(imagePullPolicy),
Env: funcEnv,
Resources: resources,
Image: runtimeImage,
},
}
if serviceAccount != "" {
function.Spec.Deployment.Spec.Template.Spec.ServiceAccountName = serviceAccount
}
if len(defaultFunction.Spec.Deployment.Spec.Template.Spec.Containers) != 0 {
function.Spec.Deployment.Spec.Template.Spec.Containers[0].VolumeMounts = defaultFunction.Spec.Deployment.Spec.Template.Spec.Containers[0].VolumeMounts
}
svcSpec := v1.ServiceSpec{
Ports: []v1.ServicePort{
{
Name: "http-function-port",
NodePort: 0,
Protocol: v1.ProtocolTCP,
},
},
Selector: funcLabels,
Type: v1.ServiceTypeClusterIP,
}
if headless {
svcSpec.ClusterIP = v1.ClusterIPNone
}
if port != 0 {
svcSpec.Ports[0].Port = port
svcSpec.Ports[0].TargetPort = intstr.FromInt(int(port))
}
if servicePort != 0 {
svcSpec.Ports[0].Port = servicePort
}
function.Spec.ServiceSpec = svcSpec
for _, secret := range secrets {
function.Spec.Deployment.Spec.Template.Spec.Volumes = append(function.Spec.Deployment.Spec.Template.Spec.Volumes, v1.Volume{
Name: secret + "-vol",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: secret,
},
},
})
function.Spec.Deployment.Spec.Template.Spec.Containers[0].VolumeMounts = append(function.Spec.Deployment.Spec.Template.Spec.Containers[0].VolumeMounts, v1.VolumeMount{
Name: secret + "-vol",
MountPath: "/" + secret,
})
}
funcNodeSelectors := parseNodeSelectors(nodeSelectors)
if len(funcNodeSelectors) == 0 && len(defaultFunction.Spec.Deployment.Spec.Template.Spec.NodeSelector) != 0 {
funcNodeSelectors = defaultFunction.Spec.Deployment.Spec.Template.Spec.NodeSelector
}
function.Spec.Deployment.Spec.Template.Spec.NodeSelector = funcNodeSelectors
return &function, nil
}
func getDeploymentStatus(cli kubernetes.Interface, funcName, ns string) (string, error) {
dpm, err := cli.AppsV1().Deployments(ns).Get(funcName, metav1.GetOptions{})
if err != nil {
return "", err
}
status := fmt.Sprintf("%d/%d", dpm.Status.ReadyReplicas, dpm.Status.Replicas)
if dpm.Status.ReadyReplicas > 0 {
status += " READY"
} else {
status += " NOT READY"
}
return status, nil
}
func getFunctions(kubelessClient versioned.Interface, namespace, functionName string) ([]*kubelessApi.Function, error) {
if functionName == "" {
f, err := kubelessClient.KubelessV1beta1().Functions(namespace).List(metav1.ListOptions{})
if err != nil {
return []*kubelessApi.Function{}, err
}
return f.Items, nil
}
f, err := kubelessClient.KubelessV1beta1().Functions(namespace).Get(functionName, metav1.GetOptions{})
if err != nil {
return []*kubelessApi.Function{}, err
}
return []*kubelessApi.Function{
f,
}, nil
}
================================================
FILE: cmd/kubeless/function/function_test.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package function
import (
"archive/tar"
"archive/zip"
"compress/gzip"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"reflect"
"testing"
kubelessApi "github.com/kubeless/kubeless/pkg/apis/kubeless/v1beta1"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/api/autoscaling/v2beta1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
func TestParseLabel(t *testing.T) {
labels := []string{
"foo=bar",
"bar:foo",
"foobar",
}
expected := map[string]string{
"foo": "bar",
"bar": "foo",
"foobar": "",
}
actual := parseLabel(labels)
if eq := reflect.DeepEqual(expected, actual); !eq {
t.Errorf("Expect %v got %v", expected, actual)
}
}
func TestParseEnv(t *testing.T) {
envs := []string{
"foo=bar",
"bar:foo",
"foobar",
"foo=bar=baz",
"qux=bar,baz",
}
expected := []v1.EnvVar{
{
Name: "foo",
Value: "bar",
},
{
Name: "bar",
Value: "foo",
},
{
Name: "foobar",
Value: "",
},
{
Name: "foo",
Value: "bar=baz",
},
{
Name: "qux",
Value: "bar,baz",
},
}
actual := parseEnv(envs)
if eq := reflect.DeepEqual(expected, actual); !eq {
t.Errorf("Expect %v got %v", expected, actual)
}
}
func TestParseNodeSelectors(t *testing.T) {
nodeSelectors := []string{
"foo=bar",
"baz:qux",
}
expected := map[string]string{
"foo": "bar",
"baz": "qux",
}
actual := parseNodeSelectors(nodeSelectors)
if eq := reflect.DeepEqual(expected, actual); !eq {
t.Errorf("Expect %v got %v", expected, actual)
}
}
func TestGetFunctionDescription(t *testing.T) {
// It should parse the given values
file, err := ioutil.TempFile("", "test")
if err != nil {
t.Error(err)
}
_, err = file.WriteString("function")
if err != nil {
t.Error(err)
}
file.Close()
defer os.Remove(file.Name()) // clean up
result, err := getFunctionDescription("test", "default", "file.handler", file.Name(), "dependencies", "runtime", "test-image", "128Mi", "", "10", "Always", "serviceAccount", 8080, 0, false, []string{"TEST=1"}, []string{"test=1"}, []string{"secretName"}, []string{"foo1=bar1", "baz1:qux1"}, kubelessApi.Function{})
if err != nil {
t.Error(err)
}
parsedMem, _ := parseResource("128Mi")
parsedCPU, _ := parseResource("")
expectedFunction := kubelessApi.Function{
TypeMeta: metav1.TypeMeta{
Kind: "Function",
APIVersion: "kubeless.io/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "default",
Labels: map[string]string{
"test": "1",
},
},
Spec: kubelessApi.FunctionSpec{
Handler: "file.handler",
Runtime: "runtime",
Function: "function",
Checksum: "sha256:78f9ac018e554365069108352dacabb7fbd15246edf19400677e3b54fe24e126",
FunctionContentType: "text",
Deps: "dependencies",
Timeout: "10",
Deployment: appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
ServiceAccountName: "serviceAccount",
Containers: []v1.Container{
{
Env: []v1.EnvVar{{
Name: "TEST",
Value: "1",
}},
Resources: v1.ResourceRequirements{
Limits: map[v1.ResourceName]resource.Quantity{
v1.ResourceMemory: parsedMem,
v1.ResourceCPU: parsedCPU,
},
Requests: map[v1.ResourceName]resource.Quantity{
v1.ResourceMemory: parsedMem,
v1.ResourceCPU: parsedCPU,
},
},
Image: "test-image",
ImagePullPolicy: v1.PullAlways,
VolumeMounts: []v1.VolumeMount{
{
Name: "secretName-vol",
MountPath: "/secretName",
},
},
},
},
Volumes: []v1.Volume{
{
Name: "secretName-vol",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: "secretName",
},
},
},
},
NodeSelector: map[string]string{
"foo1": "bar1",
"baz1": "qux1",
},
},
},
},
},
ServiceSpec: v1.ServiceSpec{
Ports: []v1.ServicePort{
{Name: "http-function-port", Protocol: "TCP", Port: 8080, TargetPort: intstr.FromInt(8080)},
},
Selector: map[string]string{
"test": "1",
},
Type: v1.ServiceTypeClusterIP,
},
},
}
if !reflect.DeepEqual(expectedFunction, *result) {
t.Errorf("Unexpected result. Expecting:\n %+v\nReceived:\n %+v", expectedFunction, *result)
}
// It should take the default values
result2, err := getFunctionDescription("test", "default", "", "", "", "", "", "", "", "", "Always", "", 8080, 0, false, []string{}, []string{}, []string{}, []string{}, expectedFunction)
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(expectedFunction, *result2) {
t.Errorf("Unexpected result. Expecting:\n %+v\n Received %+v\n", expectedFunction, *result2)
}
// Given parameters should take precedence from default values
file, err = ioutil.TempFile("", "test")
if err != nil {
t.Error(err)
}
_, err = file.WriteString("function-modified")
if err != nil {
t.Error(err)
}
file.Close()
defer os.Remove(file.Name()) // clean up
result3, err := getFunctionDescription("test", "default", "file.handler2", file.Name(), "dependencies2", "runtime2", "test-image2", "256Mi", "100m", "20", "Always", "NewServiceAccount", 8080, 0, false, []string{"TEST=2"}, []string{"test=2"}, []string{"secret2"}, []string{"foo2=bar2", "baz2:qux2"}, expectedFunction)
if err != nil {
t.Error(err)
}
parsedMem2, _ := parseResource("256Mi")
parsedCPU2, _ := parseResource("100m")
newFunction := kubelessApi.Function{
TypeMeta: metav1.TypeMeta{
Kind: "Function",
APIVersion: "kubeless.io/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "default",
Labels: map[string]string{
"test": "2",
},
},
Spec: kubelessApi.FunctionSpec{
Handler: "file.handler2",
Runtime: "runtime2",
Function: "function-modified",
FunctionContentType: "text",
Checksum: "sha256:1958eb96d7d3cadedd0f327f09322eb7db296afb282ed91aa66cb4ab0dcc3c9f",
Deps: "dependencies2",
Timeout: "20",
Deployment: appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
ServiceAccountName: "NewServiceAccount",
Containers: []v1.Container{
{
Env: []v1.EnvVar{{
Name: "TEST",
Value: "2",
}},
Resources: v1.ResourceRequirements{
Limits: map[v1.ResourceName]resource.Quantity{
v1.ResourceMemory: parsedMem2,
v1.ResourceCPU: parsedCPU2,
},
Requests: map[v1.ResourceName]resource.Quantity{
v1.ResourceMemory: parsedMem2,
v1.ResourceCPU: parsedCPU2,
},
},
Image: "test-image2",
ImagePullPolicy: v1.PullAlways,
VolumeMounts: []v1.VolumeMount{
{
Name: "secretName-vol",
MountPath: "/secretName",
}, {
Name: "secret2-vol",
MountPath: "/secret2",
},
},
},
},
Volumes: []v1.Volume{
{
Name: "secretName-vol",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: "secretName",
},
},
}, {
Name: "secret2-vol",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: "secret2",
},
},
},
},
NodeSelector: map[string]string{
"foo2": "bar2",
"baz2": "qux2",
},
},
},
},
},
ServiceSpec: v1.ServiceSpec{
Ports: []v1.ServicePort{
{Name: "http-function-port", Protocol: "TCP", Port: 8080, TargetPort: intstr.FromInt(8080)},
},
Selector: map[string]string{
"test": "2",
},
Type: v1.ServiceTypeClusterIP,
},
},
}
if !reflect.DeepEqual(newFunction, *result3) {
t.Errorf("Unexpected result. Expecting:\n %+v\n Received %+v\n", newFunction, *result3)
}
// It should detect that it is a Zip file or a compressed tar file
file, err = os.Open(file.Name())
if err != nil {
t.Error(err)
}
zipFile, err := os.Create(file.Name() + ".zip")
if err != nil {
t.Error(err)
}
defer os.Remove(zipFile.Name()) // clean up
tarGzFile, err := os.Create(file.Name() + ".tar.gz")
if err != nil {
t.Error(err)
}
defer os.Remove(tarGzFile.Name()) // clean up
zipW := zip.NewWriter(zipFile)
gzipW := gzip.NewWriter(tarGzFile)
tarW := tar.NewWriter(gzipW)
info, err := file.Stat()
if err != nil {
t.Error(err)
}
zipHeader, err := zip.FileInfoHeader(info)
if err != nil {
t.Error(err)
}
writer, err := zipW.CreateHeader(zipHeader)
if err != nil {
t.Error(err)
}
_, err = io.Copy(writer, file)
if err != nil {
t.Error(err)
}
tarHeader, err := tar.FileInfoHeader(info, info.Name())
if err != nil {
t.Error(err)
}
tarHeader.Name = file.Name()
err = tarW.WriteHeader(tarHeader)
if err != nil {
t.Error(err)
}
_, err = io.Copy(writer, file)
if err != nil {
t.Error(err)
}
file.Close()
zipW.Close()
zipFile.Close()
tarW.Close()
gzipW.Close()
tarGzFile.Close()
result4A, err := getFunctionDescription("test", "default", "file.handler", zipFile.Name(), "dependencies", "runtime", "", "", "", "", "Always", "", 8080, 0, false, []string{}, []string{}, []string{}, []string{}, expectedFunction)
if err != nil {
t.Error(err)
}
if result4A.Spec.FunctionContentType != "base64+zip" {
t.Errorf("Should return base64+zip, received %s", result4A.Spec.FunctionContentType)
}
result4B, err := getFunctionDescription("test", "default", "file.handler", tarGzFile.Name(), "dependencies", "runtime", "", "", "", "", "Always", "", 8080, 0, false, []string{}, []string{}, []string{}, []string{}, expectedFunction)
if err != nil {
t.Error(err)
}
if result4B.Spec.FunctionContentType != "base64+compressedtar" {
t.Errorf("Should return base64+compressedtar, received %s", result4B.Spec.FunctionContentType)
}
// It should maintain previous HPA definition
result5, err := getFunctionDescription("test", "default", "file.handler", file.Name(), "dependencies", "runtime", "test-image", "128Mi", "", "10", "Always", "serviceAccount", 8080, 0, false, []string{"TEST=1"}, []string{"test=1"}, []string{}, []string{}, kubelessApi.Function{
Spec: kubelessApi.FunctionSpec{
HorizontalPodAutoscaler: v2beta1.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "previous-hpa",
},
},
},
})
if result5.Spec.HorizontalPodAutoscaler.ObjectMeta.Name != "previous-hpa" {
t.Error("should maintain previous HPA definition")
}
// It should set the Port, ServicePort and headless service properly
result6, err := getFunctionDescription("test", "default", "file.handler", file.Name(), "dependencies", "runtime", "test-image", "128Mi", "", "", "Always", "serviceAccount", 9091, 9092, true, []string{}, []string{}, []string{}, []string{}, kubelessApi.Function{})
expectedPort := v1.ServicePort{
Name: "http-function-port",
Port: 9092,
TargetPort: intstr.FromInt(9091),
NodePort: 0,
Protocol: v1.ProtocolTCP,
}
if !reflect.DeepEqual(result6.Spec.ServiceSpec.Ports[0], expectedPort) {
t.Errorf("Unexpected port definition: %v", result6.Spec.ServiceSpec.Ports[0])
}
if result6.Spec.ServiceSpec.ClusterIP != v1.ClusterIPNone {
t.Errorf("Unexpected clusterIP %v", result6.Spec.ServiceSpec.ClusterIP)
}
// it should create a function from a URL
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "function")
}))
defer ts.Close()
expectedURLFunction := kubelessApi.Function{
TypeMeta: metav1.TypeMeta{
Kind: "Function",
APIVersion: "kubeless.io/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "default",
Labels: map[string]string{
"test": "1",
},
},
Spec: kubelessApi.FunctionSpec{
Handler: "file.handler",
Runtime: "runtime",
Function: ts.URL,
Checksum: "sha256:78f9ac018e554365069108352dacabb7fbd15246edf19400677e3b54fe24e126",
FunctionContentType: "url",
Deps: "dependencies",
Timeout: "10",
Deployment: appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
ServiceAccountName: "serviceAccount",
Containers: []v1.Container{
{
Env: []v1.EnvVar{{
Name: "TEST",
Value: "1",
}},
Resources: v1.ResourceRequirements{
Limits: map[v1.ResourceName]resource.Quantity{
v1.ResourceMemory: parsedMem,
v1.ResourceCPU: parsedCPU,
},
Requests: map[v1.ResourceName]resource.Quantity{
v1.ResourceMemory: parsedMem,
v1.ResourceCPU: parsedCPU,
},
},
Image: "test-image",
ImagePullPolicy: v1.PullAlways,
VolumeMounts: []v1.VolumeMount{
{
Name: "secretName-vol",
MountPath: "/secretName",
},
},
},
},
Volumes: []v1.Volume{
{
Name: "secretName-vol",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: "secretName",
},
},
},
},
NodeSelector: map[string]string{
"foo3": "bar3",
"baz3": "qux3",
},
},
},
},
},
ServiceSpec: v1.ServiceSpec{
Ports: []v1.ServicePort{
{Name: "http-function-port", Protocol: "TCP", Port: 8080, TargetPort: intstr.FromInt(8080)},
},
Selector: map[string]string{
"test": "1",
},
Type: v1.ServiceTypeClusterIP,
},
},
}
result7, err := getFunctionDescription("test", "default", "file.handler", ts.URL, "dependencies", "runtime", "test-image", "128Mi", "", "10", "Always", "serviceAccount", 8080, 0, false, []string{"TEST=1"}, []string{"test=1"}, []string{"secretName"}, []string{"foo3=bar3", "baz3:qux3"}, kubelessApi.Function{})
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(expectedURLFunction, *result7) {
t.Errorf("Unexpected result. Expecting:\n %+v\nReceived:\n %+v", expectedURLFunction, *result7)
}
// It should handle zip files and compressed tar files from a URL and detect url+zip and url+compressedtar encoding respectively
zipBytes, err := ioutil.ReadFile(zipFile.Name())
if err != nil {
t.Error(err)
}
ts2A := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write(zipBytes)
}))
defer ts2A.Close()
expectedURLFunction.Spec.FunctionContentType = "url+zip"
expectedURLFunction.Spec.Function = ts2A.URL + "/test.zip"
expectedURLFunction.Spec.Checksum, err = getSha256(zipBytes)
if err != nil {
t.Error(err)
}
result8A, err := getFunctionDescription("test", "default", "file.handler", ts2A.URL+"/test.zip", "dependencies", "runtime", "test-image", "128Mi", "", "10", "Always", "serviceAccount", 8080, 0, false, []string{"TEST=1"}, []string{"test=1"}, []string{"secretName"}, []string{"foo3=bar3", "baz3:qux3"}, kubelessApi.Function{})
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(expectedURLFunction, *result8A) {
t.Errorf("Unexpected result. Expecting:\n %+v\nReceived:\n %+v", expectedURLFunction, *result8A)
}
tarGzBytes, err := ioutil.ReadFile(tarGzFile.Name())
if err != nil {
t.Error(err)
}
ts2B := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write(tarGzBytes)
}))
defer ts2B.Close()
expectedURLFunction.Spec.FunctionContentType = "url+compressedtar"
expectedURLFunction.Spec.Function = ts2B.URL + "/test.tar.gz"
expectedURLFunction.Spec.Checksum, err = getSha256(tarGzBytes)
if err != nil {
t.Error(err)
}
result8B, err := getFunctionDescription("test", "default", "file.handler", ts2B.URL+"/test.tar.gz", "dependencies", "runtime", "test-image", "128Mi", "", "10", "Always", "serviceAccount", 8080, 0, false, []string{"TEST=1"}, []string{"test=1"}, []string{"secretName"}, []string{"foo3=bar3", "baz3:qux3"}, kubelessApi.Function{})
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(expectedURLFunction, *result8B) {
t.Errorf("Unexpected result. Expecting:\n %+v\nReceived:\n %+v", expectedURLFunction, *result8B)
}
// end test
}
func getSha256(bytes []byte) (string, error) {
h := sha256.New()
_, err := h.Write(bytes)
if err != nil {
return "", err
}
checksum := hex.EncodeToString(h.Sum(nil))
return "sha256:" + checksum, nil
}
================================================
FILE: cmd/kubeless/function/list.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package function
import (
"bytes"
"encoding/json"
"fmt"
"io"
"strings"
"github.com/ghodss/yaml"
"github.com/gosuri/uitable"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
kubelessApi "github.com/kubeless/kubeless/pkg/apis/kubeless/v1beta1"
"github.com/kubeless/kubeless/pkg/client/clientset/versioned"
"github.com/kubeless/kubeless/pkg/utils"
)
var listCmd = &cobra.Command{
Use: "list FLAG",
Aliases: []string{"ls"},
Short: "list all functions deployed to Kubeless",
Long: `list all functions deployed to Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
output, err := cmd.Flags().GetString("out")
if err != nil {
logrus.Fatal(err.Error())
}
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err.Error())
}
if ns == "" {
ns = utils.GetDefaultNamespace()
}
kubelessClient, err := utils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatalf("Can not list functions: %v", err)
}
apiV1Client := utils.GetClientOutOfCluster()
if err := doList(cmd.OutOrStdout(), kubelessClient, apiV1Client, ns, output, args); err != nil {
logrus.Fatal(err.Error())
}
},
}
func init() {
listCmd.Flags().StringP("out", "o", "", "Output format. One of: json|yaml")
listCmd.Flags().StringP("namespace", "n", "", "Specify namespace for the function")
}
func doList(w io.Writer, kubelessClient versioned.Interface, apiV1Client kubernetes.Interface, ns, output string, args []string) error {
var list []*kubelessApi.Function
if len(args) == 0 {
funcList, err := kubelessClient.KubelessV1beta1().Functions(ns).List(metav1.ListOptions{})
if err != nil {
return err
}
list = funcList.Items
} else {
list = make([]*kubelessApi.Function, 0, len(args))
for _, arg := range args {
f, err := kubelessClient.KubelessV1beta1().Functions(ns).Get(arg, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("Error listing function %s: %v", arg, err)
}
list = append(list, f)
}
}
return printFunctions(w, list, apiV1Client, output)
}
func parseDeps(deps, runtime string) (res string, err error) {
if deps != "" {
if strings.Contains(runtime, "nodejs") {
pkgjson := make(map[string]interface{})
err = json.Unmarshal([]byte(deps), &pkgjson)
if err != nil {
return
}
if pkgjson["dependencies"] != nil {
dependencies := []string{}
for pkg, ver := range pkgjson["dependencies"].(map[string]interface{}) {
dependencies = append(dependencies, pkg+": "+ver.(string))
}
res = strings.Join(dependencies, "\n")
}
} else {
res = deps
}
}
return
}
// printFunctions formats the output of function list
func printFunctions(w io.Writer, functions []*kubelessApi.Function, cli kubernetes.Interface, output string) error {
if output == "" {
table := uitable.New()
table.MaxColWidth = 50
table.Wrap = true
table.AddRow("NAME", "NAMESPACE", "HANDLER", "RUNTIME", "DEPENDENCIES", "STATUS")
for _, f := range functions {
n := f.ObjectMeta.Name
h := f.Spec.Handler
r := f.Spec.Runtime
ns := f.ObjectMeta.Namespace
status, err := getDeploymentStatus(cli, f.ObjectMeta.Name, f.ObjectMeta.Namespace)
if err != nil && k8sErrors.IsNotFound(err) {
status = "MISSING: Check controller logs"
} else if err != nil {
return err
}
deps, err := parseDeps(f.Spec.Deps, r)
if err != nil {
return err
}
table.AddRow(n, ns, h, r, deps, status)
}
fmt.Fprintln(w, table)
} else if output == "wide" {
table := uitable.New()
table.MaxColWidth = 50
table.Wrap = true
table.AddRow("NAME", "NAMESPACE", "HANDLER", "RUNTIME", "TYPE", "TOPIC", "DEPENDENCIES", "STATUS", "MEMORY", "ENV", "LABEL", "SCHEDULE")
for _, f := range functions {
n := f.ObjectMeta.Name
h := f.Spec.Handler
r := f.Spec.Runtime
deps, err := parseDeps(f.Spec.Deps, r)
if err != nil {
return err
}
ns := f.ObjectMeta.Namespace
status, err := getDeploymentStatus(cli, f.ObjectMeta.Name, f.ObjectMeta.Namespace)
if err != nil && k8sErrors.IsNotFound(err) {
status = "MISSING: Check controller logs"
} else if err != nil {
return err
}
mem := ""
env := ""
if len(f.Spec.Deployment.Spec.Template.Spec.Containers[0].Resources.Requests) != 0 {
mem = f.Spec.Deployment.Spec.Template.Spec.Containers[0].Resources.Requests.Memory().String()
}
if len(f.Spec.Deployment.Spec.Template.Spec.Containers[0].Env) != 0 {
var buffer bytes.Buffer
for _, e := range f.Spec.Deployment.Spec.Template.Spec.Containers[0].Env {
buffer.WriteString(e.Name + " = " + e.Value + "\n")
}
env = buffer.String()
}
label := ""
if len(f.ObjectMeta.Labels) > 0 {
var buffer bytes.Buffer
for k, v := range f.ObjectMeta.Labels {
buffer.WriteString(k + " : " + v + "\n")
}
label = buffer.String()
}
table.AddRow(n, ns, h, r, deps, status, mem, env, label)
}
fmt.Fprintln(w, table)
} else {
switch output {
case "json":
b, err := json.MarshalIndent(functions, "", " ")
if err != nil {
return err
}
fmt.Fprintln(w, string(b))
case "yaml":
b, err := yaml.Marshal(functions)
if err != nil {
return err
}
fmt.Fprintln(w, string(b))
default:
return fmt.Errorf("Wrong output format. Please use only json|yaml")
}
}
return nil
}
================================================
FILE: cmd/kubeless/function/list_test.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package function
import (
"bytes"
"regexp"
"strings"
"testing"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"
kubelessApi "github.com/kubeless/kubeless/pkg/apis/kubeless/v1beta1"
"github.com/kubeless/kubeless/pkg/client/clientset/versioned"
fFake "github.com/kubeless/kubeless/pkg/client/clientset/versioned/fake"
)
func listOutput(t *testing.T, client versioned.Interface, apiV1Client kubernetes.Interface, ns, output string, args []string) string {
var buf bytes.Buffer
if err := doList(&buf, client, apiV1Client, ns, output, args); err != nil {
t.Fatalf("doList returned error: %v", err)
}
return buf.String()
}
func TestList(t *testing.T) {
funcMem, _ := parseResource("128Mi")
listObj := kubelessApi.FunctionList{
Items: []*kubelessApi.Function{
{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: "myns",
},
Spec: kubelessApi.FunctionSpec{
Handler: "fhandler",
Function: "ffunction",
Runtime: "fruntime",
Deps: "fdeps",
Deployment: appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
Containers: []v1.Container{{}},
},
},
},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "bar",
Namespace: "myns",
Labels: map[string]string{
"foo": "bar",
},
},
Spec: kubelessApi.FunctionSpec{
Handler: "bhandler",
Function: "bfunction",
Runtime: "nodejs6",
Deps: "{\"dependencies\": {\"test\": \"^1.0.0\"}}",
Deployment: appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Env: []v1.EnvVar{
{
Name: "foo",
Value: "bar",
},
{
Name: "foo2",
Value: "bar2",
},
},
Resources: v1.ResourceRequirements{
Limits: map[v1.ResourceName]resource.Quantity{
v1.ResourceMemory: funcMem,
},
Requests: map[v1.ResourceName]resource.Quantity{
v1.ResourceMemory: funcMem,
},
},
},
},
},
},
},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "wrong",
Namespace: "myns",
},
Spec: kubelessApi.FunctionSpec{
Handler: "fhandler",
Function: "ffunction",
Runtime: "fruntime",
Deps: "fdeps",
Deployment: appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
Containers: []v1.Container{{}},
},
},
},
},
},
},
},
}
client := fFake.NewSimpleClientset(listObj.Items[0], listObj.Items[1], listObj.Items[2])
deploymentFoo := appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: "myns",
},
Status: appsv1.DeploymentStatus{
Replicas: int32(1),
ReadyReplicas: int32(1),
},
}
deploymentBar := appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "bar",
Namespace: "myns",
},
Status: appsv1.DeploymentStatus{
Replicas: int32(2),
ReadyReplicas: int32(0),
},
}
apiV1Client := fake.NewSimpleClientset(&deploymentFoo, &deploymentBar)
// No arg -> list everything in namespace
output := listOutput(t, client, apiV1Client, "myns", "", []string{})
t.Log("output is", output)
if !strings.Contains(output, "foo") || !strings.Contains(output, "bar") {
t.Errorf("table output didn't mention both functions")
}
// Status
m, err := regexp.MatchString("foo.*1/1 READY", output)
if err != nil {
t.Fatal(err)
}
if !m {
t.Errorf("table output didn't mention deployment status")
}
m, err = regexp.MatchString("bar.*0/2 NOT READY", output)
if err != nil {
t.Fatal(err)
}
if !m {
t.Errorf("table output didn't mention deployment status")
}
m, err = regexp.MatchString("wrong.*MISSING", output)
if err != nil {
t.Fatal(err)
}
if !m {
t.Errorf("table output didn't mention deployment status")
}
// Explicit arg(s)
output = listOutput(t, client, apiV1Client, "myns", "", []string{"foo"})
t.Log("output is", output)
if !strings.Contains(output, "foo") {
t.Errorf("table output didn't mention explicit function foo")
}
if strings.Contains(output, "bar") {
t.Errorf("table output mentions unrequested function bar")
}
if strings.Contains(output, "test: ^1.0.0") {
t.Errorf("table output doesn't show parsed dependencies")
}
// TODO: Actually validate the output of the following.
// Probably need to fix output framing first.
// json output
output = listOutput(t, client, apiV1Client, "myns", "json", []string{})
t.Log("output is", output)
if !strings.Contains(output, "foo") || !strings.Contains(output, "bar") {
t.Errorf("table output didn't mention both functions")
}
// yaml output
output = listOutput(t, client, apiV1Client, "myns", "yaml", []string{})
t.Log("output is", output)
if !strings.Contains(output, "128Mi") {
t.Errorf("table output didn't mention proper memory of function")
}
// wide output
output = listOutput(t, client, apiV1Client, "myns", "wide", []string{})
t.Log("output is", output)
if !strings.Contains(output, "foo = bar") {
t.Errorf("table output didn't mention proper env of function")
}
}
================================================
FILE: cmd/kubeless/function/logs.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package function
import (
"io"
"os"
"github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"k8s.io/api/core/v1"
)
var logsCmd = &cobra.Command{
Use: "logs <function_name> FLAG",
Short: "get logs from a running function",
Long: `get logs from a running function`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - function name")
}
funcName := args[0]
follow, err := cmd.Flags().GetBool("follow")
if err != nil {
logrus.Fatal(err)
}
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
if ns == "" {
ns = utils.GetDefaultNamespace()
}
k8sClient := utils.GetClientOutOfCluster()
if err != nil {
logrus.Fatalf("Getting log failed: %v", err)
}
pods, err := utils.GetPodsByLabel(k8sClient, ns, "function", funcName)
if err != nil {
logrus.Fatalf("Can't find the function pod: %v", err)
}
readyPod, err := utils.GetReadyPod(pods)
if err != nil {
logrus.Fatalf("No function pod is running: %v", err)
}
podLog := &v1.PodLogOptions{
Container: funcName,
Follow: follow,
}
req := k8sClient.Core().Pods(ns).GetLogs(readyPod.Name, podLog)
readCloser, err := req.Stream()
if err != nil {
logrus.Fatalf("Getting log failed: %v", err)
}
defer readCloser.Close()
io.Copy(os.Stdout, readCloser)
},
}
func init() {
logsCmd.Flags().BoolP("follow", "f", false, "Specify if the logs should be streamed.")
logsCmd.Flags().StringP("namespace", "n", "", "Specify namespace for the function")
}
================================================
FILE: cmd/kubeless/function/top.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package function
import (
"encoding/json"
"fmt"
"io"
"sort"
"time"
"github.com/ghodss/yaml"
"github.com/gosuri/uitable"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"k8s.io/client-go/kubernetes"
kubelessApi "github.com/kubeless/kubeless/pkg/apis/kubeless/v1beta1"
"github.com/kubeless/kubeless/pkg/client/clientset/versioned"
"github.com/kubeless/kubeless/pkg/utils"
)
var topCmd = &cobra.Command{
Use: "top",
Aliases: []string{"stats"},
Short: "display function metrics",
Long: `display function metrics`,
Run: func(cmd *cobra.Command, args []string) {
functionName, err := cmd.Flags().GetString("function")
if err != nil {
logrus.Fatal(err)
}
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
if ns == "" {
ns = utils.GetDefaultNamespace()
}
output, err := cmd.Flags().GetString("out")
if err != nil {
logrus.Fatal(err.Error())
}
apiV1Client := utils.GetClientOutOfCluster()
kubelessClient, err := utils.GetKubelessClientOutCluster()
handler := &utils.PrometheusMetricsHandler{}
err = doTop(cmd.OutOrStdout(), kubelessClient, apiV1Client, handler, ns, functionName, output)
if err != nil {
logrus.Fatal(err.Error())
}
},
}
func init() {
topCmd.Flags().StringP("namespace", "n", "", "Specify namespace for the function")
topCmd.Flags().StringP("function", "f", "", "Specify the function")
topCmd.Flags().StringP("out", "o", "", "Output format. One of: json|yaml")
}
func doTop(w io.Writer, kubelessClient versioned.Interface, apiV1Client kubernetes.Interface, handler utils.MetricsRetriever, ns, functionName, output string) error {
functions, err := getFunctions(kubelessClient, ns, functionName)
if err != nil {
return fmt.Errorf("Error listing functions: %v", err)
}
ch := make(chan []*utils.Metric, len(functions))
for _, f := range functions {
go func(f *kubelessApi.Function) {
ch <- utils.GetFunctionMetrics(apiV1Client, handler, ns, f.ObjectMeta.Name)
}(f)
}
var metrics []*utils.Metric
i := 0
for i < len(functions) {
select {
case r := <-ch:
metrics = append(metrics, r...)
i++
// timeout all go routines after 5 seconds to avoid hanging at the cmd line
case <-time.After(5 * time.Second):
i = len(functions)
}
}
// sort the results - useful when using 'watch kubeless function top'
sort.Slice(metrics, func(i, j int) bool {
return metrics[i].FunctionName < metrics[j].FunctionName
})
return printTop(w, metrics, apiV1Client, output)
}
func printTop(w io.Writer, metrics []*utils.Metric, cli kubernetes.Interface, output string) error {
if output == "" {
table := uitable.New()
table.MaxColWidth = 50
table.Wrap = true
table.AddRow("NAME", "NAMESPACE", "METHOD", "TOTAL_CALLS", "TOTAL_FAILURES", "TOTAL_DURATION_SECONDS", "AVG_DURATION_SECONDS", "MESSAGE")
for _, f := range metrics {
if f.Message != "" {
table.AddRow(f.FunctionName, f.Namespace, "", "", "", "", "", f.Message)
} else {
table.AddRow(f.FunctionName, f.Namespace, f.Method, f.TotalCalls, f.TotalFailures, f.TotalDurationSeconds, f.AvgDurationSeconds, "")
}
}
fmt.Fprintln(w, table)
} else {
switch output {
case "json":
b, err := json.MarshalIndent(metrics, "", " ")
if err != nil {
return err
}
fmt.Fprintln(w, string(b))
case "yaml":
b, err := yaml.Marshal(metrics)
if err != nil {
return err
}
fmt.Fprintln(w, string(b))
default:
return fmt.Errorf("Wrong output format. Please use only json|yaml")
}
}
return nil
}
================================================
FILE: cmd/kubeless/function/top_test.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package function
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"
kubelessApi "github.com/kubeless/kubeless/pkg/apis/kubeless/v1beta1"
"github.com/kubeless/kubeless/pkg/client/clientset/versioned"
fFake "github.com/kubeless/kubeless/pkg/client/clientset/versioned/fake"
"github.com/kubeless/kubeless/pkg/utils"
)
type testMetricsHandler struct{}
// handler used for testing purposes only
// satisfies the MetricsRetriever interface, gets metrics from the test http server (URL to test http server stored in svc.SelfLink field)
func (h *testMetricsHandler) GetRawMetrics(apiClient kubernetes.Interface, namespace, functionName string) ([]byte, error) {
svc, err := apiClient.CoreV1().Services(namespace).Get(functionName, metav1.GetOptions{})
if err != nil {
return []byte{}, err
}
b, err := http.Get(svc.SelfLink)
if err != nil {
return nil, err
}
defer b.Body.Close()
return ioutil.ReadAll(b.Body)
}
func topOutput(t *testing.T, client versioned.Interface, apiV1Client kubernetes.Interface, h utils.MetricsRetriever, ns, functionName, output string) string {
var buf bytes.Buffer
if err := doTop(&buf, client, apiV1Client, h, ns, functionName, output); err != nil {
t.Fatalf("doTop returned error: %v", err)
}
return buf.String()
}
func TestTop(t *testing.T) {
// setup test server to serve the /metrics endpoint
ts2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w,
`# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 1.6846e-05
go_gc_duration_seconds{quantile="0.25"} 3.9124e-05
go_gc_duration_seconds{quantile="0.5"} 0.000147183
go_gc_duration_seconds{quantile="0.75"} 0.000958419
go_gc_duration_seconds{quantile="1"} 0.00796035
go_gc_duration_seconds_sum 2.50781303
go_gc_duration_seconds_count 3424
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 7
# HELP go_info Information about the Go environment.
# TYPE go_info gauge
go_info{version="go1.10.2"} 1
# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use.
# TYPE go_memstats_alloc_bytes gauge
go_memstats_alloc_bytes 2.28336e+06
# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed.
# TYPE go_memstats_alloc_bytes_total counter
go_memstats_alloc_bytes_total 9.9682544e+09
# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table.
# TYPE go_memstats_buck_hash_sys_bytes gauge
go_memstats_buck_hash_sys_bytes 1.500081e+06
# HELP go_memstats_frees_total Total number of frees.
# TYPE go_memstats_frees_total counter
go_memstats_frees_total 1.2698678e+07
# HELP go_memstats_gc_cpu_fraction The fraction of this program's available CPU time used by the GC since the program started.
# TYPE go_memstats_gc_cpu_fraction gauge
go_memstats_gc_cpu_fraction 0.0001214506861340198
# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata.
# TYPE go_memstats_gc_sys_bytes gauge
go_memstats_gc_sys_bytes 405504
# HELP go_memstats_heap_alloc_bytes Number of heap bytes allocated and still in use.
# TYPE go_memstats_heap_alloc_bytes gauge
go_memstats_heap_alloc_bytes 2.28336e+06
# HELP go_memstats_heap_idle_bytes Number of heap bytes waiting to be used.
# TYPE go_memstats_heap_idle_bytes gauge
go_memstats_heap_idle_bytes 2.6624e+06
# HELP go_memstats_heap_inuse_bytes Number of heap bytes that are in use.
# TYPE go_memstats_heap_inuse_bytes gauge
go_memstats_heap_inuse_bytes 3.072e+06
# HELP go_memstats_heap_objects Number of allocated objects.
# TYPE go_memstats_heap_objects gauge
go_memstats_heap_objects 6280
# HELP go_memstats_heap_released_bytes Number of heap bytes released to OS.
# TYPE go_memstats_heap_released_bytes gauge
go_memstats_heap_released_bytes 0
# HELP go_memstats_heap_sys_bytes Number of heap bytes obtained from system.
# TYPE go_memstats_heap_sys_bytes gauge
go_memstats_heap_sys_bytes 5.7344e+06
# HELP go_memstats_last_gc_time_seconds Number of seconds since 1970 of last garbage collection.
# TYPE go_memstats_last_gc_time_seconds gauge
go_memstats_last_gc_time_seconds 1.528573398809276e+09
# HELP go_memstats_lookups_total Total number of pointer lookups.
# TYPE go_memstats_lookups_total counter
go_memstats_lookups_total 88701
# HELP go_memstats_mallocs_total Total number of mallocs.
# TYPE go_memstats_mallocs_total counter
go_memstats_mallocs_total 1.2704958e+07
# HELP go_memstats_mcache_inuse_bytes Number of bytes in use by mcache structures.
# TYPE go_memstats_mcache_inuse_bytes gauge
go_memstats_mcache_inuse_bytes 3472
# HELP go_memstats_mcache_sys_bytes Number of bytes used for mcache structures obtained from system.
# TYPE go_memstats_mcache_sys_bytes gauge
go_memstats_mcache_sys_bytes 16384
# HELP go_memstats_mspan_inuse_bytes Number of bytes in use by mspan structures.
# TYPE go_memstats_mspan_inuse_bytes gauge
go_memstats_mspan_inuse_bytes 25688
# HELP go_memstats_mspan_sys_bytes Number of bytes used for mspan structures obtained from system.
# TYPE go_memstats_mspan_sys_bytes gauge
go_memstats_mspan_sys_bytes 32768
# HELP go_memstats_next_gc_bytes Number of heap bytes when next garbage collection will take place.
# TYPE go_memstats_next_gc_bytes gauge
go_memstats_next_gc_bytes 4.194304e+06
# HELP go_memstats_other_sys_bytes Number of bytes used for other system allocations.
# TYPE go_memstats_other_sys_bytes gauge
go_memstats_other_sys_bytes 738631
# HELP go_memstats_stack_inuse_bytes Number of bytes in use by the stack allocator.
# TYPE go_memstats_stack_inuse_bytes gauge
go_memstats_stack_inuse_bytes 557056
# HELP go_memstats_stack_sys_bytes Number of bytes obtained from system for stack allocator.
# TYPE go_memstats_stack_sys_bytes gauge
go_memstats_stack_sys_bytes 557056
# HELP go_memstats_sys_bytes Number of bytes obtained from system.
# TYPE go_memstats_sys_bytes gauge
go_memstats_sys_bytes 8.984824e+06
# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge
go_threads 10
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 25.88
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 1.048576e+06
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 8
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 1.3942784e+07
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.52853941225e+09
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 1.57294592e+08
# HELP promhttp_metric_handler_requests_in_flight Current number of scrapes being served.
# TYPE promhttp_metric_handler_requests_in_flight gauge
promhttp_metric_handler_requests_in_flight 1
# HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code.
# TYPE promhttp_metric_handler_requests_total counter
promhttp_metric_handler_requests_total{code="200"} 10798
promhttp_metric_handler_requests_total{code="500"} 0
promhttp_metric_handler_requests_total{code="503"} 0
`)
}))
defer ts2.Close()
// setup test server to serve the /metrics endpoint
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w,
`# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 815255552.0
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 25001984.0
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1528507334.03
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 54.72
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 8.0
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 1048576.0
# HELP python_info Python platform information
# TYPE python_info gauge
python_info{implementation="CPython",major="2",minor="7",patchlevel="9",version="2.7.9"} 1.0
# HELP function_failures_total Number of exceptions in user function
# TYPE function_failures_total counter
function_failures_total{method="GET"} 0.0
function_failures_total{method="POST"} 0.0
# HELP function_calls_total Number of calls to user function
# TYPE function_calls_total counter
function_calls_total{method="GET"} 254.0
function_calls_total{method="POST"} 296.0
# HELP function_duration_seconds Duration of user function in seconds
# TYPE function_duration_seconds histogram
function_duration_seconds_bucket{le="0.005",method="GET"} 8.0
function_duration_seconds_bucket{le="0.01",method="GET"} 191.0
function_duration_seconds_bucket{le="0.025",method="GET"} 248.0
function_duration_seconds_bucket{le="0.05",method="GET"} 253.0
function_duration_seconds_bucket{le="0.075",method="GET"} 253.0
function_duration_seconds_bucket{le="0.1",method="GET"} 253.0
function_duration_seconds_bucket{le="0.25",method="GET"} 254.0
function_duration_seconds_bucket{le="0.5",method="GET"} 254.0
function_duration_seconds_bucket{le="0.75",method="GET"} 254.0
function_duration_seconds_bucket{le="1.0",method="GET"} 254.0
function_duration_seconds_bucket{le="2.5",method="GET"} 254.0
function_duration_seconds_bucket{le="5.0",method="GET"} 254.0
function_duration_seconds_bucket{le="7.5",method="GET"} 254.0
function_duration_seconds_bucket{le="10.0",method="GET"} 254.0
function_duration_seconds_bucket{le="+Inf",method="GET"} 254.0
function_duration_seconds_count{method="GET"} 254.0
function_duration_seconds_sum{method="GET"} 2.863368272781372
function_duration_seconds_bucket{le="0.005",method="POST"} 1.0
function_duration_seconds_bucket{le="0.01",method="POST"} 157.0
function_duration_seconds_bucket{le="0.025",method="POST"} 296.0
function_duration_seconds_bucket{le="0.05",method="POST"} 296.0
function_duration_seconds_bucket{le="0.075",method="POST"} 296.0
function_duration_seconds_bucket{le="0.1",method="POST"} 296.0
function_duration_seconds_bucket{le="0.25",method="POST"} 296.0
function_duration_seconds_bucket{le="0.5",method="POST"} 296.0
function_duration_seconds_bucket{le="0.75",method="POST"} 296.0
function_duration_seconds_bucket{le="1.0",method="POST"} 296.0
function_duration_seconds_bucket{le="2.5",method="POST"} 296.0
function_duration_seconds_bucket{le="5.0",method="POST"} 296.0
function_duration_seconds_bucket{le="7.5",method="POST"} 296.0
function_duration_seconds_bucket{le="10.0",method="POST"} 296.0
function_duration_seconds_bucket{le="+Inf",method="POST"} 296.0
function_duration_seconds_count{method="POST"} 296.0
function_duration_seconds_sum{method="POST"} 3.4116291999816895
`)
}))
defer ts.Close()
function1Name := "pyFunc"
function2Name := "goFunc"
namespace := "myns"
listObj := kubelessApi.FunctionList{
Items: []*kubelessApi.Function{
{
ObjectMeta: metav1.ObjectMeta{
Name: function1Name,
Namespace: namespace,
},
Spec: kubelessApi.FunctionSpec{
Handler: "fhandler",
Function: function1Name,
Runtime: "pyruntime",
Deps: "pydeps",
Deployment: appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
Containers: []v1.Container{{}},
},
},
},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: function2Name,
Namespace: namespace,
},
Spec: kubelessApi.FunctionSpec{
Handler: "gohandler",
Function: function2Name,
Runtime: "goruntime",
Deps: "godeps",
Deployment: appsv1.Deployment{
Spec: appsv1.DeploymentSpec{
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
Containers: []v1.Container{{}},
},
},
},
},
},
},
},
}
client := fFake.NewSimpleClientset(listObj.Items[0], listObj.Items[1])
deploymentPy := appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: function1Name,
Namespace: namespace,
},
Status: appsv1.DeploymentStatus{
Replicas: int32(1),
ReadyReplicas: int32(1),
},
}
deploymentGo := appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: function2Name,
Namespace: namespace,
},
Status: appsv1.DeploymentStatus{
Replicas: int32(1),
ReadyReplicas: int32(1),
},
}
serviceGo := v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: function2Name,
Namespace: namespace,
SelfLink: ts2.URL,
},
Spec: v1.ServiceSpec{
Ports: []v1.ServicePort{
{
Name: "p1",
Port: int32(8080),
TargetPort: intstr.FromInt(8080),
NodePort: 0,
Protocol: v1.ProtocolTCP,
},
},
},
}
servicePy := v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: function1Name,
Namespace: namespace,
SelfLink: ts.URL,
},
Spec: v1.ServiceSpec{
Ports: []v1.ServicePort{
{
Name: "p1",
Port: int32(8080),
TargetPort: intstr.FromInt(8080),
NodePort: 0,
Protocol: v1.ProtocolTCP,
},
},
},
}
apiV1Client := fake.NewSimpleClientset(&deploymentPy, &servicePy, &deploymentGo, &serviceGo)
handler := &testMetricsHandler{}
// List multiple functions
output := topOutput(t, client, apiV1Client, handler, namespace, "", "")
t.Log("output is", output)
if !strings.Contains(output, function1Name) || !strings.Contains(output, function2Name) || !strings.Contains(output, namespace) {
t.Errorf("table output didn't match FUNCTION or NAMESPACE")
}
if !strings.Contains(output, "GET") || !strings.Contains(output, "POST") {
t.Errorf("table output didn't match on METHOD")
}
if !strings.Contains(output, "2.86336") || !strings.Contains(output, "3.41162") {
t.Errorf("table output didn't match on TOTAL_DURATION_SECONDS")
}
// verify calculated fields
if !strings.Contains(output, "0.0112731") || !strings.Contains(output, "0.0115257") {
t.Errorf("table output didn't match on AVG_DURATION_SECONDS")
}
// Get single function
output = topOutput(t, client, apiV1Client, handler, namespace, function2Name, "")
t.Log("output is", output)
if strings.Contains(output, function1Name) || !strings.Contains(output, function2Name) || !strings.Contains(output, namespace) {
t.Errorf("table output didn't match FUNCTION or NAMESPACE")
}
// json output
output = topOutput(t, client, apiV1Client, handler, namespace, "", "json")
t.Log("output is", output)
if !strings.Contains(output, function1Name) || !strings.Contains(output, function2Name) || !strings.Contains(output, namespace) {
t.Errorf("table output didn't match FUNCTION or NAMESPACE")
}
if !strings.Contains(output, "GET") || !strings.Contains(output, "POST") {
t.Errorf("table output didn't match on METHOD")
}
if !strings.Contains(output, "2.86336") || !strings.Contains(output, "3.41162") {
t.Errorf("table output didn't match on TOTAL_DURATION_SECONDS")
}
// verify calculated fields
if !strings.Contains(output, "0.0112731") || !strings.Contains(output, "0.0115257") {
t.Errorf("table output didn't match on AVG_DURATION_SECONDS")
}
// yaml output
output = topOutput(t, client, apiV1Client, handler, namespace, "", "yaml")
t.Log("output is", output)
if !strings.Contains(output, function1Name) || !strings.Contains(output, function2Name) || !strings.Contains(output, namespace) {
t.Errorf("table output didn't match FUNCTION or NAMESPACE")
}
if !strings.Contains(output, "GET") || !strings.Contains(output, "POST") {
t.Errorf("table output didn't match on METHOD")
}
if !strings.Contains(output, "2.86336") || !strings.Contains(output, "3.41162") {
t.Errorf("table output didn't match on TOTAL_DURATION_SECONDS")
}
// verify calculated fields
if !strings.Contains(output, "0.0112731") || !strings.Contains(output, "0.0115257") {
t.Errorf("table output didn't match on AVG_DURATION_SECONDS")
}
}
================================================
FILE: cmd/kubeless/function/update.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package function
import (
"encoding/json"
"fmt"
"strings"
"github.com/ghodss/yaml"
"github.com/kubeless/kubeless/pkg/langruntime"
"github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
var updateCmd = &cobra.Command{
Use: "update <function_name> FLAG",
Short: "update a function on Kubeless",
Long: `update a function on Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
cli := utils.GetClientOutOfCluster()
apiExtensionsClientset := utils.GetAPIExtensionsClientOutOfCluster()
config, err := utils.GetKubelessConfig(cli, apiExtensionsClientset)
if err != nil {
logrus.Fatalf("Unable to read the configmap: %v", err)
}
var lr = langruntime.New(config)
lr.ReadConfigMap()
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - function name")
}
funcName := args[0]
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
var nsArg string
if ns == "" {
ns = utils.GetDefaultNamespace()
} else {
nsArg = fmt.Sprintf(" -n %s", ns)
}
handler, err := cmd.Flags().GetString("handler")
if err != nil {
logrus.Fatal(err)
}
file, err := cmd.Flags().GetString("from-file")
if err != nil {
logrus.Fatal(err)
}
secrets, err := cmd.Flags().GetStringSlice("secrets")
if err != nil {
logrus.Fatal(err)
}
serviceAccount, err := cmd.Flags().GetString("service-account")
if err != nil {
logrus.Fatal(err)
}
runtime, err := cmd.Flags().GetString("runtime")
if err != nil {
logrus.Fatal(err)
}
if runtime != "" && !lr.IsValidRuntime(runtime) {
logrus.Fatalf("Invalid runtime: %s. Supported runtimes are: %s",
runtime, strings.Join(lr.GetRuntimes(), ", "))
}
labels, err := cmd.Flags().GetStringSlice("label")
if err != nil {
logrus.Fatal(err)
}
envs, err := cmd.Flags().GetStringSlice("env")
if err != nil {
logrus.Fatal(err)
}
runtimeImage, err := cmd.Flags().GetString("runtime-image")
if err != nil {
logrus.Fatal(err)
}
imagePullPolicy, err := cmd.Flags().GetString("image-pull-policy")
if err != nil {
logrus.Fatal(err)
}
if imagePullPolicy != "IfNotPresent" && imagePullPolicy != "Always" && imagePullPolicy != "Never" {
err := fmt.Errorf("image-pull-policy must be {IfNotPresent|Always|Never}")
logrus.Fatal(err)
}
mem, err := cmd.Flags().GetString("memory")
if err != nil {
logrus.Fatal(err)
}
cpu, err := cmd.Flags().GetString("cpu")
if err != nil {
logrus.Fatal(err)
}
timeout, err := cmd.Flags().GetString("timeout")
if err != nil {
logrus.Fatal(err)
}
deps, err := cmd.Flags().GetString("dependencies")
if err != nil {
logrus.Fatal(err)
}
funcDeps := ""
if deps != "" {
contentType, err := utils.GetContentType(deps)
if err != nil {
logrus.Fatal(err)
}
funcDeps, _, err = utils.ParseContent(deps, contentType)
if err != nil {
logrus.Fatal(err)
}
}
headless, err := cmd.Flags().GetBool("headless")
if err != nil {
logrus.Fatal(err)
}
port, err := cmd.Flags().GetInt32("port")
if err != nil {
logrus.Fatal(err)
}
if port <= 0 || port > 65535 {
logrus.Fatalf("Invalid port number %d specified", port)
}
servicePort, err := cmd.Flags().GetInt32("servicePort")
if err != nil {
logrus.Fatal(err)
}
if servicePort < 0 || servicePort > 65535 {
logrus.Fatalf("Invalid servicePort number %d specified", servicePort)
}
output, err := cmd.Flags().GetString("output")
if err != nil {
logrus.Fatal(err)
}
dryrun, err := cmd.Flags().GetBool("dryrun")
if err != nil {
logrus.Fatal(err)
}
nodeSelectors, err := cmd.Flags().GetStringSlice("node-selectors")
if err != nil {
logrus.Fatal(err)
}
previousFunction, err := utils.GetFunction(funcName, ns)
if err != nil {
logrus.Fatal(err)
}
f, err := getFunctionDescription(funcName, ns, handler, file, funcDeps, runtime, runtimeImage, mem, cpu, timeout, imagePullPolicy, serviceAccount, port, servicePort, headless, envs, labels, secrets, nodeSelectors, previousFunction)
if err != nil {
logrus.Fatal(err)
}
if dryrun == true {
if output == "json" {
j, err := json.MarshalIndent(f, "", " ")
if err != nil {
logrus.Fatal(err)
}
fmt.Println(string(j[:]))
return
} else if output == "yaml" {
y, err := yaml.Marshal(f)
if err != nil {
logrus.Fatal(err)
}
fmt.Println(string(y[:]))
return
} else {
logrus.Infof("Output format needs to be yaml or json")
return
}
}
kubelessClient, err := utils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatal(err)
}
logrus.Infof("Redeploying function...")
err = utils.PatchFunctionCustomResource(kubelessClient, f)
if err != nil {
logrus.Fatal(err)
}
logrus.Infof("Function %s submitted for deployment", funcName)
logrus.Infof("Check the deployment status executing 'kubeless function ls %s%s'", funcName, nsArg)
},
}
func init() {
updateCmd.Flags().StringP("runtime", "r", "", "Specify runtime")
updateCmd.Flags().StringP("handler", "", "", "Specify handler")
updateCmd.Flags().StringP("from-file", "f", "", "Specify code file or a URL to the code file")
updateCmd.Flags().StringP("memory", "", "", "Request amount of memory for the function")
updateCmd.Flags().StringP("cpu", "", "", "Request amount of cpu for the function.")
updateCmd.Flags().StringSliceP("label", "l", []string{}, "Specify labels of the function")
updateCmd.Flags().StringSliceP("secrets", "", []string{}, "Specify Secrets to be mounted to the functions container. For example: --secrets mySecret")
updateCmd.Flags().StringSliceP("env", "e", []string{}, "Specify environment variable of the function")
updateCmd.Flags().StringSliceP("node-selectors", "", []string{}, "Specify node selectors for the function")
updateCmd.Flags().StringP("service-account", "", "", "Specify service account for the function. For example: --service-account controller-acct")
updateCmd.Flags().StringP("namespace", "n", "", "Specify namespace for the function")
updateCmd.Flags().StringP("dependencies", "d", "", "Specify a file containing list of dependencies for the function")
updateCmd.Flags().StringP("runtime-image", "", "", "Custom runtime image")
updateCmd.Flags().StringP("image-pull-policy", "", "Always", "Image pull policy")
updateCmd.Flags().StringP("timeout", "", "180", "Maximum timeout (in seconds) for the function to complete its execution")
updateCmd.Flags().Bool("headless", false, "Deploy http-based function without a single service IP and load balancing support from Kubernetes. See: https://kubernetes.io/docs/concepts/services-networking/service/#headless-services")
updateCmd.Flags().Int32("port", 8080, "Deploy http-based function with a custom port")
updateCmd.Flags().Int32("servicePort", 0, "Deploy http-based function with a custom service port")
updateCmd.Flags().Bool("dryrun", false, "Output JSON manifest of the function without creating it")
updateCmd.Flags().StringP("output", "o", "yaml", "Output format")
}
================================================
FILE: cmd/kubeless/getserverconfig/getServerConfig.go
================================================
package getserverconfig
import (
"strings"
"github.com/kubeless/kubeless/pkg/langruntime"
"github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
// GetServerConfigCmd contains first-class command for displaying the current server config
var GetServerConfigCmd = &cobra.Command{
Use: "get-server-config",
Short: "Print the current configuration of the controller",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
cli := utils.GetClientOutOfCluster()
apiExtensionsClientset := utils.GetAPIExtensionsClientOutOfCluster()
config, err := utils.GetKubelessConfig(cli, apiExtensionsClientset)
if err != nil {
logrus.Fatalf("Unable to read the configmap: %v", err)
}
var lr = langruntime.New(config)
lr.ReadConfigMap()
logrus.Info("Current Server Config:")
logrus.Infof("Supported Runtimes are: %s",
strings.Join(lr.GetRuntimes(), ", "))
},
}
================================================
FILE: cmd/kubeless/kubeless.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Serverless framework for Kubernetes.
package main
import (
"os"
"github.com/kubeless/kubeless/cmd/kubeless/autoscale"
"github.com/kubeless/kubeless/cmd/kubeless/completion"
"github.com/kubeless/kubeless/cmd/kubeless/function"
"github.com/kubeless/kubeless/cmd/kubeless/getserverconfig"
"github.com/kubeless/kubeless/cmd/kubeless/topic"
"github.com/kubeless/kubeless/cmd/kubeless/trigger"
"github.com/kubeless/kubeless/cmd/kubeless/version"
"github.com/spf13/cobra"
)
var globalUsage = `` //TODO: add explanation
func newRootCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "kubeless",
Short: "Serverless framework for Kubernetes",
Long: globalUsage,
}
cmd.AddCommand(function.FunctionCmd, topic.TopicCmd, version.VersionCmd, autoscale.AutoscaleCmd, getserverconfig.GetServerConfigCmd, trigger.TriggerCmd, completion.CompletionCmd)
return cmd
}
func main() {
cmd := newRootCmd()
if err := cmd.Execute(); err != nil {
os.Exit(1)
}
}
================================================
FILE: cmd/kubeless/topic/topic.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package topic
import (
"github.com/spf13/cobra"
)
// TopicCmd contains first-class command for topic
var TopicCmd = &cobra.Command{
Use: "topic SUBCOMMAND",
Short: "manage message topics in Kubeless",
Long: `topic command allows user to list, create, delete topics on Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}
func init() {
cmds := []*cobra.Command{topicCreateCmd, topicDeleteCmd, topicListCmd, topicPublishCmd}
for _, cmd := range cmds {
TopicCmd.AddCommand(cmd)
cmd.Flags().StringP("kafka-namespace", "", "kubeless", "Namespace where kafka-controller is deployed. It will default to 'kubeless'")
}
}
================================================
FILE: cmd/kubeless/topic/topicCreate.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package topic
import (
"fmt"
"io"
"github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
var topicCreateCmd = &cobra.Command{
Use: "create <topic_name> FLAG",
Short: "create a topic to Kubeless",
Long: `create a topic to Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - topic name")
}
ctlNamespace, err := cmd.Flags().GetString("kafka-namespace")
if err != nil {
logrus.Fatal(err)
}
topicName := args[0]
conf, err := utils.BuildOutOfClusterConfig()
if err != nil {
logrus.Fatal(err)
}
k8sClientSet := utils.GetClientOutOfCluster()
err = createTopic(conf, k8sClientSet, ctlNamespace, topicName, cmd.OutOrStdout())
if err != nil {
logrus.Fatal(err)
}
},
}
func createTopic(conf *rest.Config, clientset kubernetes.Interface, ctlNamespace, topicName string, out io.Writer) error {
command := []string{
"bash", "/opt/bitnami/kafka/bin/kafka-topics.sh",
"--zookeeper", "zookeeper." + ctlNamespace + ":2181",
"--replication-factor", "1",
"--partitions", "1",
"--create",
"--topic", topicName,
}
return execCommand(conf, clientset, ctlNamespace, command, out)
}
// wrapper of kubectl exec
// execCommand executes a command to kafka pod
func execCommand(conf *rest.Config, k8sClientSet kubernetes.Interface, ctlNamespace string, command []string, out io.Writer) error {
pods, err := utils.GetPodsByLabel(k8sClientSet, ctlNamespace, "kubeless", "kafka")
if err != nil {
return fmt.Errorf("Can't find the kafka pod: %v", err)
} else if len(pods.Items) == 0 {
return fmt.Errorf("Can't find any kafka pod")
}
cmd := utils.Cmd{
Stdout: out,
Stderr: out,
}
rt, err := utils.ExecRoundTripper(conf, cmd.RoundTripCallback)
if err != nil {
return err
}
opts := v1.PodExecOptions{
Stdin: false,
Stdout: true,
Stderr: true,
Container: "broker",
Command: command,
}
req, err := utils.Exec(k8sClientSet.Core(), pods.Items[0].Name, ctlNamespace, opts)
if err != nil {
return err
}
_, err = rt.RoundTrip(req)
return err
}
================================================
FILE: cmd/kubeless/topic/topicDelete.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package topic
import (
"io"
"github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
var topicDeleteCmd = &cobra.Command{
Use: "delete <topic_name>",
Short: "delete a topic from Kubeless",
Long: `delete a topic from Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - topic name")
}
ctlNamespace, err := cmd.Flags().GetString("kafka-namespace")
if err != nil {
logrus.Fatal(err)
}
topicName := args[0]
conf, err := utils.BuildOutOfClusterConfig()
if err != nil {
logrus.Fatal(err)
}
k8sClientSet := utils.GetClientOutOfCluster()
err = deleteTopic(conf, k8sClientSet, ctlNamespace, topicName, cmd.OutOrStdout())
if err != nil {
logrus.Fatal(err)
}
},
}
func deleteTopic(conf *rest.Config, clientset kubernetes.Interface, ctlNamespace, topicName string, out io.Writer) error {
command := []string{
"bash", "/opt/bitnami/kafka/bin/kafka-topics.sh",
"--zookeeper", "zookeeper." + ctlNamespace + ":2181",
"--delete",
"--topic", topicName,
}
return execCommand(conf, clientset, ctlNamespace, command, out)
}
================================================
FILE: cmd/kubeless/topic/topicList.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package topic
import (
"io"
"github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
var topicListCmd = &cobra.Command{
Use: "list FLAG",
Aliases: []string{"ls"},
Short: "list all topics created in Kubeless",
Long: `list all topics created in Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
ctlNamespace, err := cmd.Flags().GetString("kafka-namespace")
if err != nil {
logrus.Fatal(err)
}
conf, err := utils.BuildOutOfClusterConfig()
if err != nil {
logrus.Fatal(err)
}
k8sClientSet := utils.GetClientOutOfCluster()
err = listTopic(conf, k8sClientSet, ctlNamespace, cmd.OutOrStdout())
if err != nil {
logrus.Fatal(err)
}
},
}
func listTopic(conf *rest.Config, clientset kubernetes.Interface, ctlNamespace string, out io.Writer) error {
command := []string{
"bash", "/opt/bitnami/kafka/bin/kafka-topics.sh",
"--zookeeper", "zookeeper." + ctlNamespace + ":2181",
"--list",
}
return execCommand(conf, clientset, ctlNamespace, command, out)
}
================================================
FILE: cmd/kubeless/topic/topicPublish.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package topic
import (
"fmt"
"io"
"github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
var topicPublishCmd = &cobra.Command{
Use: "publish FLAG",
Short: "publish message to a topic",
Long: `publish message to a topic`,
Run: func(cmd *cobra.Command, args []string) {
data, err := cmd.Flags().GetString("data")
if err != nil {
logrus.Fatal(err)
}
topic, err := cmd.Flags().GetString("topic")
if err != nil {
logrus.Fatal(err)
}
ctlNamespace, err := cmd.Flags().GetString("kafka-namespace")
if err != nil {
logrus.Fatal(err)
}
conf, err := utils.BuildOutOfClusterConfig()
if err != nil {
logrus.Fatal(err)
}
k8sClientSet := utils.GetClientOutOfCluster()
err = publishTopic(conf, k8sClientSet, ctlNamespace, topic, data, cmd.OutOrStdout())
if err != nil {
logrus.Fatal(err)
}
},
}
func publishTopic(conf *rest.Config, clientset kubernetes.Interface, namespace, topic, data string, out io.Writer) error {
command := []string{
"bash", "/opt/bitnami/kafka/bin/kafka-console-producer.sh",
"--broker-list", "localhost:9092",
"--topic", topic,
}
// Can't just use `execCommand` since we want to specify stdin
// TODO(gus): refactor better.
pods, err := utils.GetPodsByLabel(clientset, namespace, "kubeless", "kafka")
if err != nil {
return fmt.Errorf("Can't find the kafka pod: %v", err)
} else if len(pods.Items) == 0 {
return fmt.Errorf("Can't find any kafka pod")
}
pRead, pWrite := io.Pipe()
cmd := utils.Cmd{
Stdin: pRead,
Stdout: out,
Stderr: out,
}
rt, err := utils.ExecRoundTripper(conf, cmd.RoundTripCallback)
if err != nil {
return err
}
go func() {
io.WriteString(pWrite, data+"\n")
pWrite.Close()
}()
opts := v1.PodExecOptions{
Stdin: true,
Stdout: true,
Stderr: true,
TTY: true,
Container: "broker",
Command: command,
}
req, err := utils.Exec(clientset.Core(), pods.Items[0].Name, namespace, opts)
if err != nil {
return err
}
_, err = rt.RoundTrip(req)
return err
}
func init() {
topicPublishCmd.Flags().StringP("data", "", "", "Specify data for function")
topicPublishCmd.Flags().StringP("topic", "", "kubeless", "Specify topic name")
}
================================================
FILE: cmd/kubeless/trigger/cronjob/create.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cronjob
import (
"fmt"
"github.com/robfig/cron"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
cronjobApi "github.com/kubeless/cronjob-trigger/pkg/apis/kubeless/v1beta1"
cronjobUtils "github.com/kubeless/cronjob-trigger/pkg/utils"
kubelessUtils "github.com/kubeless/kubeless/pkg/utils"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var createCmd = &cobra.Command{
Use: "create <cronjob_trigger_name> FLAG",
Short: "Create a cron job trigger",
Long: `Create a cron job trigger`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - cronjob trigger name")
}
triggerName := args[0]
schedule, err := cmd.Flags().GetString("schedule")
if err != nil {
logrus.Fatal(err)
}
if _, err := cron.ParseStandard(schedule); err != nil {
logrus.Fatalf("Invalid value for --schedule. " + err.Error())
}
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
if ns == "" {
ns = kubelessUtils.GetDefaultNamespace()
}
functionName, err := cmd.Flags().GetString("function")
if err != nil {
logrus.Fatal(err)
}
dryrun, err := cmd.Flags().GetBool("dryrun")
if err != nil {
logrus.Fatal(err)
}
output, err := cmd.Flags().GetString("output")
if err != nil {
logrus.Fatal(err)
}
payload, err := cmd.Flags().GetString("payload")
if err != nil {
logrus.Fatal(err)
}
payloadFromFile, err := cmd.Flags().GetString("payload-from-file")
if err != nil {
logrus.Fatal(err)
}
if len(payload) > 0 && len(payloadFromFile) > 0 {
err := "You can't provide both raw payload and a payload file"
logrus.Fatal(err)
}
kubelessClient, err := kubelessUtils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatalf("Can not create out-of-cluster client: %v", err)
}
cronJobClient, err := cronjobUtils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatalf("Can not create out-of-cluster client: %v", err)
}
_, err = kubelessUtils.GetFunctionCustomResource(kubelessClient, functionName, ns)
if err != nil {
logrus.Fatalf("Unable to find Function %s in namespace %s. Error %s", functionName, ns, err)
}
parsedPayload, err := parsePayload(payload, payloadFromFile)
if err != nil {
logrus.Fatalf("Unable to parse the payload of Function %s in namespace %s. Error %s", functionName, ns, err)
}
cronJobTrigger := cronjobApi.CronJobTrigger{}
cronJobTrigger.TypeMeta = metav1.TypeMeta{
Kind: "CronJobTrigger",
APIVersion: "kubeless.io/v1beta1",
}
cronJobTrigger.ObjectMeta = metav1.ObjectMeta{
Name: triggerName,
Namespace: ns,
}
cronJobTrigger.ObjectMeta.Labels = map[string]string{
"created-by": "kubeless",
}
cronJobTrigger.Spec.FunctionName = functionName
cronJobTrigger.Spec.Schedule = schedule
cronJobTrigger.Spec.Payload = parsedPayload
if dryrun == true {
res, err := kubelessUtils.DryRunFmt(output, cronJobTrigger)
if err != nil {
logrus.Fatal(err)
}
fmt.Println(res)
return
}
err = cronjobUtils.CreateCronJobCustomResource(cronJobClient, &cronJobTrigger)
if err != nil {
logrus.Fatalf("Failed to create cronjob trigger object %s in namespace %s. Error: %s", triggerName, ns, err)
}
logrus.Infof("Cronjob trigger %s created in namespace %s successfully!", triggerName, ns)
},
}
func init() {
createCmd.Flags().StringP("namespace", "n", "", "Specify namespace for the cronjob trigger")
createCmd.Flags().StringP("schedule", "", "", "Specify schedule in cron format for scheduled function")
createCmd.Flags().StringP("function", "", "", "Name of the function to be associated with trigger")
createCmd.MarkFlagRequired("function")
createCmd.MarkFlagRequired("schedule")
createCmd.Flags().Bool("dryrun", false, "Output JSON manifest of the function without creating it")
createCmd.Flags().StringP("output", "o", "yaml", "Output format")
createCmd.Flags().StringP("payload", "p", "", "Specify a stringified JSON data to pass to function upon execution")
createCmd.Flags().StringP("payload-from-file", "f", "", "Specify a payload file to use. It must be a JSON file")
}
================================================
FILE: cmd/kubeless/trigger/cronjob/cronjob_trigger.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cronjob
import (
"encoding/json"
"fmt"
"path/filepath"
kubelessutil "github.com/kubeless/kubeless/pkg/utils"
"github.com/spf13/cobra"
)
// CronjobTriggerCmd command for CronJob trigger commands
var CronjobTriggerCmd = &cobra.Command{
Use: "cronjob SUBCOMMAND",
Short: "cronjob trigger specific operations",
Long: `cronjob trigger command allows user to create, list, update, delete cronjob triggers running on Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}
func init() {
CronjobTriggerCmd.AddCommand(createCmd)
CronjobTriggerCmd.AddCommand(deleteCmd)
CronjobTriggerCmd.AddCommand(listCmd)
CronjobTriggerCmd.AddCommand(updateCmd)
}
func parsePayload(content string, file string) (interface{}, error) {
if len(file) > 0 {
content, err := getPayloadRawContent(file)
if err != nil {
return nil, err
}
return parsePayloadContent(content), nil
}
return parsePayloadContent(content), nil
}
func getPayloadRawContent(file string) (string, error) {
contentType, err := kubelessutil.GetContentType(file)
if err != nil {
return "", err
}
content, _, err := kubelessutil.ParseContent(file, contentType)
if err != nil {
return "", err
}
ext := filepath.Ext(file)
if ext != ".json" {
return "", fmt.Errorf("Sorry, we can't parse %s files yet", ext)
}
return content, nil
}
func parsePayloadContent(raw string) interface{} {
var payload map[string]interface{}
err := json.Unmarshal([]byte(raw), &payload)
if err != nil {
return fmt.Errorf("Found an error during JSON parsing on your payload: %s", err)
}
return payload
}
================================================
FILE: cmd/kubeless/trigger/cronjob/delete.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cronjob
import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
cronjobUtils "github.com/kubeless/cronjob-trigger/pkg/utils"
kubelessUtils "github.com/kubeless/kubeless/pkg/utils"
)
var deleteCmd = &cobra.Command{
Use: "delete <cronjob_trigger_name>",
Short: "delete a cronjob trigger from Kubeless",
Long: `delete a cronjob trigger from Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - cronjob trigger name")
}
triggerName := args[0]
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
if ns == "" {
ns = kubelessUtils.GetDefaultNamespace()
}
kubelessClient, err := cronjobUtils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatal(err)
}
err = cronjobUtils.DeleteCronJobCustomResource(kubelessClient, triggerName, ns)
if err != nil {
logrus.Fatalf("Failed to delete Cronjob trigger object %s in namespace %s. Error: %s", triggerName, ns, err)
}
logrus.Infof("Cronjob trigger %s deleted from namespace %s successfully!", triggerName, ns)
},
}
func init() {
deleteCmd.Flags().StringP("namespace", "n", "", "Specify namespace of the Cronjob trigger")
}
================================================
FILE: cmd/kubeless/trigger/cronjob/list.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cronjob
import (
"fmt"
"io"
"github.com/gosuri/uitable"
"github.com/kubeless/cronjob-trigger/pkg/client/clientset/versioned"
cronjobUtils "github.com/kubeless/cronjob-trigger/pkg/utils"
kubelessUtils "github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var listCmd = &cobra.Command{
Use: "list FLAG",
Aliases: []string{"ls"},
Short: "list all Cronjob triggers deployed to Kubeless",
Long: `list all Cronjob triggers deployed to Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err.Error())
}
if ns == "" {
ns = kubelessUtils.GetDefaultNamespace()
}
kubelessClient, err := cronjobUtils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatalf("Can not create out-of-cluster client: %v", err)
}
if err := doList(cmd.OutOrStdout(), kubelessClient, ns); err != nil {
logrus.Fatal(err.Error())
}
},
}
func init() {
listCmd.Flags().StringP("namespace", "n", "", "Specify namespace for the function")
}
func doList(w io.Writer, kubelessClient versioned.Interface, ns string) error {
triggersList, err := kubelessClient.KubelessV1beta1().CronJobTriggers(ns).List(metav1.ListOptions{})
if err != nil {
return err
}
table := uitable.New()
table.MaxColWidth = 50
table.Wrap = true
table.AddRow("NAME", "NAMESPACE", "SCHEDULE", "FUNCTION NAME")
for _, trigger := range triggersList.Items {
table.AddRow(trigger.Name, trigger.Namespace, trigger.Spec.Schedule, trigger.Spec.FunctionName)
}
fmt.Fprintln(w, table)
return nil
}
================================================
FILE: cmd/kubeless/trigger/cronjob/update.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cronjob
import (
"fmt"
"github.com/robfig/cron"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
cronjobUtils "github.com/kubeless/cronjob-trigger/pkg/utils"
kubelessUtils "github.com/kubeless/kubeless/pkg/utils"
)
var updateCmd = &cobra.Command{
Use: "update <cronjob_trigger_name> FLAG",
Short: "Update a cron job trigger",
Long: `Update a cron job trigger`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - cronjob trigger name")
}
triggerName := args[0]
schedule, err := cmd.Flags().GetString("schedule")
if err != nil {
logrus.Fatal(err)
}
if schedule != "" {
if _, err := cron.ParseStandard(schedule); err != nil {
logrus.Fatalf("Invalid value for --schedule. " + err.Error())
}
}
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
if ns == "" {
ns = kubelessUtils.GetDefaultNamespace()
}
functionName, err := cmd.Flags().GetString("function")
if err != nil {
logrus.Fatal(err)
}
dryrun, err := cmd.Flags().GetBool("dryrun")
if err != nil {
logrus.Fatal(err)
}
output, err := cmd.Flags().GetString("output")
if err != nil {
logrus.Fatal(err)
}
payload, err := cmd.Flags().GetString("payload")
if err != nil {
logrus.Fatal(err)
}
payloadFromFile, err := cmd.Flags().GetString("payload-from-file")
if err != nil {
logrus.Fatal(err)
}
if len(payload) > 0 && len(payloadFromFile) > 0 {
err := "You can't provide both raw payload and a payload file"
logrus.Fatal(err)
}
kubelessClient, err := kubelessUtils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatalf("Can not create out-of-cluster client: %v", err)
}
cronJobClient, err := cronjobUtils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatalf("Can not create out-of-cluster client: %v", err)
}
_, err = kubelessUtils.GetFunctionCustomResource(kubelessClient, functionName, ns)
if err != nil {
logrus.Fatalf("Unable to find Function %s in namespace %s. Error %s", triggerName, ns, err)
}
parsedPayload, err := parsePayload(payload, payloadFromFile)
if err != nil {
logrus.Fatalf("Unable to parse the payload of Function %s in namespace %s. Error %s", functionName, ns, err)
}
cronJobTrigger, err := cronjobUtils.GetCronJobCustomResource(cronJobClient, triggerName, ns)
if err != nil {
logrus.Fatalf("Unable to find Cronjob trigger %s in namespace %s. Error %s", triggerName, ns, err)
}
cronJobTrigger.Spec.FunctionName = functionName
cronJobTrigger.Spec.Schedule = schedule
cronJobTrigger.Spec.Payload = parsedPayload
if dryrun == true {
res, err := kubelessUtils.DryRunFmt(output, cronJobTrigger)
if err != nil {
logrus.Fatal(err)
}
fmt.Println(res)
return
}
err = cronjobUtils.UpdateCronJobCustomResource(cronJobClient, cronJobTrigger)
if err != nil {
logrus.Fatalf("Failed to update cronjob trigger object %s in namespace %s. Error: %s", triggerName, ns, err)
}
logrus.Infof("Cronjob trigger %s updated in namespace %s successfully!", triggerName, ns)
},
}
func init() {
updateCmd.Flags().StringP("namespace", "n", "", "Specify namespace of the cronjob trigger")
updateCmd.Flags().StringP("schedule", "", "", "Specify schedule in cron format for scheduled function")
updateCmd.Flags().StringP("function", "", "", "Name of the function to be associated with trigger")
updateCmd.Flags().Bool("dryrun", false, "Output JSON manifest of the function without creating it")
updateCmd.Flags().StringP("output", "o", "yaml", "Output format")
updateCmd.Flags().StringP("payload", "p", "", "Specify a stringified JSON data to pass to function upon execution")
updateCmd.Flags().StringP("payload-from-file", "f", "", "Specify a payload file to use. It must be a JSON file")
}
================================================
FILE: cmd/kubeless/trigger/http/create.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package http
import (
"fmt"
httpApi "github.com/kubeless/http-trigger/pkg/apis/kubeless/v1beta1"
httpUtils "github.com/kubeless/http-trigger/pkg/utils"
kubelessUtils "github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var createCmd = &cobra.Command{
Use: "create <http_trigger_name> FLAG",
Short: "Create a http trigger",
Long: `Create a http trigger`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - http trigger name")
}
triggerName := args[0]
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
if ns == "" {
ns = kubelessUtils.GetDefaultNamespace()
}
path, err := cmd.Flags().GetString("path")
if err != nil {
logrus.Fatal(err)
}
functionName, err := cmd.Flags().GetString("function-name")
if err != nil {
logrus.Fatal(err)
}
dryrun, err := cmd.Flags().GetBool("dryrun")
if err != nil {
logrus.Fatal(err)
}
output, err := cmd.Flags().GetString("output")
if err != nil {
logrus.Fatal(err)
}
kubelessClient, err := kubelessUtils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatalf("Can not create out-of-cluster client: %v", err)
}
_, err = kubelessUtils.GetFunctionCustomResource(kubelessClient, functionName, ns)
if err != nil {
logrus.Fatalf("Unable to find Function %s in namespace %s. Error %s", functionName, ns, err)
}
httpTrigger := httpApi.HTTPTrigger{}
httpTrigger.TypeMeta = metav1.TypeMeta{
Kind: "HTTPTrigger",
APIVersion: "kubeless.io/v1beta1",
}
httpTrigger.ObjectMeta = metav1.ObjectMeta{
Name: triggerName,
Namespace: ns,
}
httpTrigger.ObjectMeta.Labels = map[string]string{
"created-by": "kubeless",
}
httpTrigger.Spec.FunctionName = functionName
if len(path) != 0 {
httpTrigger.Spec.Path = path
}
enableTLSAcme, err := cmd.Flags().GetBool("enableTLSAcme")
if err != nil {
logrus.Fatal(err)
}
httpTrigger.Spec.TLSAcme = enableTLSAcme
corsEnabled, err := cmd.Flags().GetBool("cors-enable")
if err != nil {
logrus.Fatal(err)
}
httpTrigger.Spec.CorsEnable = corsEnabled
tlsSecret, err := cmd.Flags().GetString("tls-secret")
if err != nil {
logrus.Fatal(err)
}
if enableTLSAcme && len(tlsSecret) > 0 {
logrus.Fatalf("Cannot specify both --enableTLSAcme and --tls-secret")
}
httpTrigger.Spec.TLSSecret = tlsSecret
gateway, err := cmd.Flags().GetString("gateway")
if err != nil {
logrus.Fatal(err)
}
if gateway != "nginx" && gateway != "traefik" && gateway != "kong" {
logrus.Fatalf("Unsupported gateway %s", gateway)
}
httpTrigger.Spec.Gateway = gateway
hostName, err := cmd.Flags().GetString("hostname")
if err != nil {
logrus.Fatal(err)
}
if hostName == "" && gateway == "nginx" {
// We assume that Nginx will be listening in the port 80
// of the cluster plublic IP
config, err := kubelessUtils.BuildOutOfClusterConfig()
if err != nil {
logrus.Fatal(err)
}
hostName, err = httpUtils.GetLocalHostname(config, functionName)
if err != nil {
logrus.Fatal(err)
}
}
if hostName == "" {
logrus.Fatalf("The --hostname flag is required")
}
httpTrigger.Spec.HostName = hostName
basicAuthSecret, err := cmd.Flags().GetString("basic-auth-secret")
if err != nil {
logrus.Fatal(err)
}
httpTrigger.Spec.BasicAuthSecret = basicAuthSecret
if dryrun == true {
res, err := kubelessUtils.DryRunFmt(output, httpTrigger)
if err != nil {
logrus.Fatal(err)
}
fmt.Println(res)
return
}
httpClient, err := httpUtils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatalf("Can not create out-of-cluster client: %v", err)
}
err = httpUtils.CreateHTTPTriggerCustomResource(httpClient, &httpTrigger)
if err != nil {
logrus.Fatalf("Failed to deploy HTTP trigger %s in namespace %s. Error: %s", triggerName, ns, err)
}
logrus.Infof("HTTP trigger %s created in namespace %s successfully!", triggerName, ns)
},
}
func init() {
createCmd.Flags().StringP("namespace", "n", "", "Specify namespace for the HTTP trigger")
createCmd.Flags().StringP("function-name", "", "", "Name of the function to be associated with trigger")
createCmd.Flags().StringP("path", "", "", "Ingress path for the function")
createCmd.Flags().StringP("hostname", "", "", "Specify a valid hostname for the function")
createCmd.Flags().BoolP("enableTLSAcme", "", false, "If true, routing rule will be configured for use with kube-lego")
createCmd.Flags().StringP("gateway", "", "nginx", "Specify a valid gateway for the Ingress. Supported: nginx, traefik, kong")
createCmd.Flags().StringP("basic-auth-secret", "", "", "Specify an existing secret name for basic authentication")
createCmd.Flags().StringP("tls-secret", "", "", "Specify an existing secret that contains a TLS private key and certificate to secure ingress")
createCmd.Flags().Bool("dryrun", false, "Output JSON manifest of the function without creating it")
createCmd.Flags().StringP("output", "o", "yaml", "Output format")
createCmd.Flags().BoolP("cors-enable", "", false, "If true then cors will be enabled on Http Trigger")
createCmd.MarkFlagRequired("function-name")
}
================================================
FILE: cmd/kubeless/trigger/http/delete.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package http
import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
httpUtils "github.com/kubeless/http-trigger/pkg/utils"
kubelessUtils "github.com/kubeless/kubeless/pkg/utils"
)
var deleteCmd = &cobra.Command{
Use: "delete <http_trigger_name>",
Short: "Delete a HTTP trigger",
Long: `Delete a HTTP trigger`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - Kafka trigger name")
}
triggerName := args[0]
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
if ns == "" {
ns = kubelessUtils.GetDefaultNamespace()
}
httpClient, err := httpUtils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatalf("Can not create out-of-cluster client: %v", err)
}
err = httpUtils.DeleteHTTPTriggerCustomResource(httpClient, triggerName, ns)
if err != nil {
logrus.Fatalf("Failed to delete HTTP trigger object %s in namespace %s. Error: %s", triggerName, ns, err)
}
logrus.Infof("HTTP trigger %s deleted from namespace %s successfully!", triggerName, ns)
},
}
func init() {
deleteCmd.Flags().StringP("namespace", "n", "", "Specify namespace for the function")
}
================================================
FILE: cmd/kubeless/trigger/http/http_trigger.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package http
import (
"github.com/spf13/cobra"
)
// HTTPTriggerCmd command for http trigger commands
var HTTPTriggerCmd = &cobra.Command{
Use: "http SUBCOMMAND",
Short: "http trigger specific operations",
Long: `http trigger command allows user to create, list, update, delete http triggers running on Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}
func init() {
HTTPTriggerCmd.AddCommand(createCmd)
HTTPTriggerCmd.AddCommand(deleteCmd)
HTTPTriggerCmd.AddCommand(listCmd)
HTTPTriggerCmd.AddCommand(updateCmd)
}
================================================
FILE: cmd/kubeless/trigger/http/list.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package http
import (
"fmt"
"io"
"github.com/gosuri/uitable"
"github.com/kubeless/http-trigger/pkg/client/clientset/versioned"
httpUtils "github.com/kubeless/http-trigger/pkg/utils"
kubelessUtils "github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var listCmd = &cobra.Command{
Use: "list FLAG",
Aliases: []string{"ls"},
Short: "list all HTTP triggers deployed to Kubeless",
Long: `list all HTTP triggers deployed to Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err.Error())
}
if ns == "" {
ns = kubelessUtils.GetDefaultNamespace()
}
httpClient, err := httpUtils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatalf("Can not create out-of-cluster client: %v", err)
}
if err := doList(cmd.OutOrStdout(), httpClient, ns); err != nil {
logrus.Fatal(err.Error())
}
},
}
func init() {
listCmd.Flags().StringP("namespace", "n", "", "Specify namespace for the function")
}
func doList(w io.Writer, kubelessClient versioned.Interface, ns string) error {
triggersList, err := kubelessClient.KubelessV1beta1().HTTPTriggers(ns).List(metav1.ListOptions{})
if err != nil {
return err
}
table := uitable.New()
table.MaxColWidth = 50
table.Wrap = true
table.AddRow("NAME", "NAMESPACE", "FUNCTION NAME")
for _, trigger := range triggersList.Items {
table.AddRow(trigger.Name, trigger.Namespace, trigger.Spec.FunctionName)
}
fmt.Fprintln(w, table)
return nil
}
================================================
FILE: cmd/kubeless/trigger/http/update.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package http
import (
"fmt"
httpUtils "github.com/kubeless/http-trigger/pkg/utils"
kubelessUtils "github.com/kubeless/kubeless/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
var updateCmd = &cobra.Command{
Use: "update <http_trigger_name> FLAG",
Short: "Update a http trigger",
Long: `Update a http trigger`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - http trigger name")
}
triggerName := args[0]
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
if ns == "" {
ns = kubelessUtils.GetDefaultNamespace()
}
kubelessClient, err := kubelessUtils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatalf("Can not create out-of-cluster client: %v", err)
}
httpClient, err := httpUtils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatalf("Can not create out-of-cluster client: %v", err)
}
httpTrigger, err := httpUtils.GetHTTPTriggerCustomResource(httpClient, triggerName, ns)
if err != nil {
logrus.Fatalf("Unable to find HTTP trigger %s in namespace %s. Error %s", triggerName, ns, err)
}
functionName, err := cmd.Flags().GetString("function-name")
if err != nil {
logrus.Fatal(err)
}
if functionName != "" {
_, err = kubelessUtils.GetFunctionCustomResource(kubelessClient, functionName, ns)
if err != nil {
logrus.Fatalf("Unable to find Function %s in namespace %s. Error %s", functionName, ns, err)
}
httpTrigger.Spec.FunctionName = functionName
}
path, err := cmd.Flags().GetString("path")
if err != nil {
logrus.Fatal(err)
}
if path != "" {
httpTrigger.Spec.Path = path
}
hostName, err := cmd.Flags().GetString("hostname")
if err != nil {
logrus.Fatal(err)
}
if hostName != "" {
httpTrigger.Spec.HostName = hostName
}
enableTLSAcme, err := cmd.Flags().GetBool("enableTLSAcme")
if err != nil {
logrus.Fatal(err)
}
httpTrigger.Spec.TLSAcme = enableTLSAcme
tlsSecret, err := cmd.Flags().GetString("tls-secret")
if err != nil {
logrus.Fatal(err)
}
if enableTLSAcme && len(tlsSecret) > 0 {
logrus.Fatalf("Cannot specify both --enableTLSAcme and --tls-secret")
}
if tlsSecret != "" {
httpTrigger.Spec.TLSSecret = tlsSecret
}
gateway, err := cmd.Flags().GetString("gateway")
if err != nil {
logrus.Fatal(err)
}
if gateway != "" {
httpTrigger.Spec.Gateway = gateway
}
basicAuthSecret, err := cmd.Flags().GetString("basic-auth-secret")
if err != nil {
logrus.Fatal(err)
}
if basicAuthSecret != "" {
httpTrigger.Spec.BasicAuthSecret = basicAuthSecret
}
dryrun, err := cmd.Flags().GetBool("dryrun")
if err != nil {
logrus.Fatal(err)
}
output, err := cmd.Flags().GetString("output")
if err != nil {
logrus.Fatal(err)
}
if dryrun == true {
res, err := kubelessUtils.DryRunFmt(output, httpTrigger)
if err != nil {
logrus.Fatal(err)
}
fmt.Println(res)
return
}
err = httpUtils.UpdateHTTPTriggerCustomResource(httpClient, httpTrigger)
if err != nil {
logrus.Fatalf("Failed to deploy HTTP trigger %s in namespace %s. Error: %s", triggerName, ns, err)
}
logrus.Infof("HTTP trigger %s updated in namespace %s successfully!", triggerName, ns)
},
}
func init() {
updateCmd.Flags().StringP("namespace", "n", "", "Specify namespace for the HTTP trigger")
updateCmd.Flags().StringP("function-name", "", "", "Name of the function to be associated with trigger")
updateCmd.Flags().StringP("path", "", "", "Ingress path for the function")
updateCmd.Flags().StringP("hostname", "", "", "Specify a valid hostname for the function")
updateCmd.Flags().BoolP("enableTLSAcme", "", false, "If true, routing rule will be configured for use with kube-lego")
updateCmd.Flags().StringP("gateway", "", "", "Specify a valid gateway for the Ingress")
updateCmd.Flags().StringP("basic-auth-secret", "", "", "Specify an existing secret name for basic authentication")
updateCmd.Flags().StringP("tls-secret", "", "", "Specify an existing secret that contains a TLS private key and certificate to secure ingress")
updateCmd.Flags().Bool("dryrun", false, "Output JSON manifest of the function without creating it")
updateCmd.Flags().StringP("output", "o", "yaml", "Output format")
}
================================================
FILE: cmd/kubeless/trigger/kafka/create.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kafka
import (
"fmt"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
kafkaApi "github.com/kubeless/kafka-trigger/pkg/apis/kubeless/v1beta1"
kafkaUtils "github.com/kubeless/kafka-trigger/pkg/utils"
kubelessUtils "github.com/kubeless/kubeless/pkg/utils"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var createCmd = &cobra.Command{
Use: "create <kafka_trigger_name> FLAG",
Short: "Create a Kafka trigger",
Long: `Create a Kafka trigger`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - kafka trigger name")
}
triggerName := args[0]
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
if ns == "" {
ns = kubelessUtils.GetDefaultNamespace()
}
topic, err := cmd.Flags().GetString("trigger-topic")
if err != nil {
logrus.Fatal(err)
}
functionSelector, err := cmd.Flags().GetString("function-selector")
if err != nil {
logrus.Fatal(err)
}
dryrun, err := cmd.Flags().GetBool("dryrun")
if err != nil {
logrus.Fatal(err)
}
output, err := cmd.Flags().GetString("output")
if err != nil {
logrus.Fatal(err)
}
labelSelector, err := metav1.ParseToLabelSelector(functionSelector)
if err != nil {
logrus.Fatal("Invalid lable selector specified " + err.Error())
}
kafkaTrigger := kafkaApi.KafkaTrigger{}
kafkaTrigger.TypeMeta = metav1.TypeMeta{
Kind: "KafkaTrigger",
APIVersion: "kubeless.io/v1beta1",
}
kafkaTrigger.ObjectMeta = metav1.ObjectMeta{
Name: triggerName,
Namespace: ns,
}
kafkaTrigger.ObjectMeta.Labels = map[string]string{
"created-by": "kubeless",
}
kafkaTrigger.Spec.FunctionSelector.MatchLabels = labelSelector.MatchLabels
kafkaTrigger.Spec.Topic = topic
if dryrun == true {
res, err := kubelessUtils.DryRunFmt(output, kafkaTrigger)
if err != nil {
logrus.Fatal(err)
}
fmt.Println(res)
return
}
kafkaClient, err := kafkaUtils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatalf("Can not create out-of-cluster client: %v", err)
}
err = kafkaUtils.CreateKafkaTriggerCustomResource(kafkaClient, &kafkaTrigger)
if err != nil {
logrus.Fatalf("Failed to create Kafka trigger object %s in namespace %s. Error: %s", triggerName, ns, err)
}
logrus.Infof("Kafka trigger %s created in namespace %s successfully!", triggerName, ns)
},
}
func init() {
createCmd.Flags().StringP("namespace", "n", "", "Specify namespace for the kafka trigger")
createCmd.Flags().StringP("trigger-topic", "", "", "Specify topic to listen to in Kafka broker")
createCmd.Flags().StringP("function-selector", "", "", "Selector (label query) to select function on (e.g. --function-selector key1=value1,key2=value2)")
createCmd.MarkFlagRequired("trigger-topic")
createCmd.MarkFlagRequired("function-selector")
createCmd.Flags().Bool("dryrun", false, "Output JSON manifest of the function without creating it")
createCmd.Flags().StringP("output", "o", "yaml", "Output format")
}
================================================
FILE: cmd/kubeless/trigger/kafka/delete.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kafka
import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
kafkaUtils "github.com/kubeless/kafka-trigger/pkg/utils"
kubelessUtils "github.com/kubeless/kubeless/pkg/utils"
)
var deleteCmd = &cobra.Command{
Use: "delete <kafka_trigger_name>",
Short: "Delete a Kafka trigger",
Long: `Delete a Kafka trigger`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
logrus.Fatal("Need exactly one argument - Kafka trigger name")
}
triggerName := args[0]
ns, err := cmd.Flags().GetString("namespace")
if err != nil {
logrus.Fatal(err)
}
if ns == "" {
ns = kubelessUtils.GetDefaultNamespace()
}
kafkaClient, err := kafkaUtils.GetKubelessClientOutCluster()
if err != nil {
logrus.Fatalf("Can not create out-of-cluster client: %v", err)
}
err = kafkaUtils.DeleteKafkaTriggerCustomResource(kafkaClient, triggerName, ns)
if err != nil {
logrus.Fatalf("Failed to delete Kafka trigger object %s in namespace %s. Error: %s", triggerName, ns, err)
}
logrus.Infof("Kafka trigger %s deleted from namespace %s successfully!", triggerName, ns)
},
}
func init() {
deleteCmd.Flags().StringP("namespace", "n", "", "Specify namespace of the Kafka trigger")
}
================================================
FILE: cmd/kubeless/trigger/kafka/kafka_trigger.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kafka
import (
"github.com/spf13/cobra"
)
// KafkaTriggerCmd command for Kafka trigger commands
var KafkaTriggerCmd = &cobra.Command{
Use: "kafka SUBCOMMAND",
Short: "kafka trigger specific operations",
Long: `kafka trigger command allows user to create, list, update, delete kafka triggers running on Kubeless`,
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}
func init() {
KafkaTriggerCmd.AddCommand(createCmd)
KafkaTriggerCmd.AddCommand(deleteCmd)
KafkaTriggerCmd.AddCommand(listCmd)
KafkaTriggerCmd.AddCommand(updateCmd)
}
================================================
FILE: cmd/kubeless/trigger/kafka/list.go
================================================
/*
Copyright (c) 2016-2017 Bitnami
Licensed under the Apache License, Version 2.0 (the "License");
yo
gitextract_a4vhstu0/
├── .circleci/
│ └── config.yml
├── .github/
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── gcloud.json.enc
│ └── issue_template.md
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── OWNERS
├── README.md
├── cmd/
│ ├── function-controller/
│ │ └── function-controller.go
│ └── kubeless/
│ ├── autoscale/
│ │ ├── autoscale.go
│ │ ├── autoscaleCreate.go
│ │ ├── autoscaleDelete.go
│ │ ├── autoscaleList.go
│ │ ├── autoscaleList_test.go
│ │ └── autoscale_test.go
│ ├── completion/
│ │ └── completion.go
│ ├── function/
│ │ ├── call.go
│ │ ├── delete.go
│ │ ├── deploy.go
│ │ ├── describe.go
│ │ ├── function.go
│ │ ├── function_test.go
│ │ ├── list.go
│ │ ├── list_test.go
│ │ ├── logs.go
│ │ ├── top.go
│ │ ├── top_test.go
│ │ └── update.go
│ ├── getserverconfig/
│ │ └── getServerConfig.go
│ ├── kubeless.go
│ ├── topic/
│ │ ├── topic.go
│ │ ├── topicCreate.go
│ │ ├── topicDelete.go
│ │ ├── topicList.go
│ │ └── topicPublish.go
│ ├── trigger/
│ │ ├── cronjob/
│ │ │ ├── create.go
│ │ │ ├── cronjob_trigger.go
│ │ │ ├── delete.go
│ │ │ ├── list.go
│ │ │ └── update.go
│ │ ├── http/
│ │ │ ├── create.go
│ │ │ ├── delete.go
│ │ │ ├── http_trigger.go
│ │ │ ├── list.go
│ │ │ └── update.go
│ │ ├── kafka/
│ │ │ ├── create.go
│ │ │ ├── delete.go
│ │ │ ├── kafka_trigger.go
│ │ │ ├── list.go
│ │ │ └── update.go
│ │ ├── kinesis/
│ │ │ ├── create.go
│ │ │ ├── delete.go
│ │ │ ├── kinesis_trigger.go
│ │ │ ├── list.go
│ │ │ ├── publish.go
│ │ │ ├── stream_create.go
│ │ │ └── update.go
│ │ ├── nats/
│ │ │ ├── create.go
│ │ │ ├── delete.go
│ │ │ ├── list.go
│ │ │ ├── nats_trigger.go
│ │ │ ├── publish.go
│ │ │ └── update.go
│ │ └── trigger.go
│ └── version/
│ └── version.go
├── docker/
│ ├── controller-manager
│ ├── dev-environment/
│ │ ├── Dockerfile
│ │ └── entry-point.sh
│ ├── event-sources/
│ │ └── kubernetes/
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ └── events.py
│ ├── function-controller/
│ │ └── Dockerfile
│ ├── function-image-builder/
│ │ ├── Dockerfile
│ │ └── entrypoint.sh
│ ├── runtime/
│ │ └── README.md
│ └── unzip/
│ └── Dockerfile
├── docs/
│ ├── GKE-deployment.md
│ ├── README.md
│ ├── advanced-function-deployment.md
│ ├── architecture.md
│ ├── autoscaling.md
│ ├── building-functions.md
│ ├── cronjob-triggers.md
│ ├── debug-functions.md
│ ├── debugging.md
│ ├── dev-guide.md
│ ├── function-controller-configuration.md
│ ├── http-triggers.md
│ ├── implementing-new-runtime.md
│ ├── implementing-new-trigger.md
│ ├── kubeless-functions.md
│ ├── kubeless-on-AKS.md
│ ├── misc/
│ │ ├── kafka-pv-gke.yaml
│ │ ├── kubeless-grafana-dashboard.json
│ │ └── zookeeper-pv-gke.yaml
│ ├── monitoring.md
│ ├── proposals/
│ │ ├── decoupling-triggers-and-runtimes.md
│ │ └── http-triggers.md
│ ├── pubsub-functions.md
│ ├── quick-start.md
│ ├── release-flow.md
│ ├── runtimes.md
│ ├── streaming-functions.md
│ ├── triggers.md
│ ├── troubleshooting.md
│ └── use-existing-kafka.md
├── examples/
│ ├── Makefile
│ ├── README.md
│ ├── ballerina/
│ │ ├── hello_with_conf/
│ │ │ ├── hello_with_conf.bal
│ │ │ └── kubeless.toml
│ │ ├── helloget.bal
│ │ └── hellowithdata.bal
│ ├── dotnetcore/
│ │ ├── dependency-yaml.cs
│ │ ├── dependency-yaml.csproj
│ │ ├── fibonacci.cs
│ │ ├── fibonacci.csproj
│ │ ├── helloget.cs
│ │ ├── helloget.csproj
│ │ ├── hellowithdata.cs
│ │ └── hellowithdata.csproj
│ ├── golang/
│ │ ├── go.mod
│ │ ├── helloget.go
│ │ ├── hellowithdata.go
│ │ └── hellowithdeps.go
│ ├── java/
│ │ ├── HelloGet.java
│ │ ├── HelloWithData.java
│ │ ├── HelloWithDeps.java
│ │ └── pom.xml
│ ├── jvm/
│ │ ├── Readme.md
│ │ ├── java/
│ │ │ ├── Readme.md
│ │ │ ├── build/
│ │ │ │ └── libs/
│ │ │ │ └── java-0.1-all.jar
│ │ │ ├── build.gradle
│ │ │ ├── src/
│ │ │ │ └── main/
│ │ │ │ └── java/
│ │ │ │ └── io/
│ │ │ │ └── ino/
│ │ │ │ └── Handler.java
│ │ │ └── test-java-jvm.jar
│ │ └── scala/
│ │ ├── Readme.md
│ │ ├── build.sbt
│ │ ├── project/
│ │ │ ├── assembly.sbt
│ │ │ └── build.properties
│ │ └── src/
│ │ └── main/
│ │ └── scala/
│ │ └── de/
│ │ └── inoio/
│ │ └── Handler.scala
│ ├── nodejs/
│ │ ├── function.yaml
│ │ ├── function1.yaml
│ │ ├── helloFunctions.tar.bz2
│ │ ├── helloFunctions.tar.xz
│ │ ├── helloget.js
│ │ ├── hellostream.js
│ │ ├── hellowithdata.js
│ │ ├── hellowithdeps.js
│ │ ├── index.js
│ │ └── package.json
│ ├── php/
│ │ ├── composer.json
│ │ ├── helloget.php
│ │ ├── hellowithdata.php
│ │ └── hellowithdeps.php
│ ├── python/
│ │ ├── Dockerfile
│ │ ├── function.yaml
│ │ ├── function1.yaml
│ │ ├── helloget.py
│ │ ├── hellowithdata.py
│ │ ├── hellowithdeps.py
│ │ ├── hellowithdepshelper.py
│ │ └── requirements.txt
│ └── ruby/
│ ├── Gemfile
│ ├── function.yaml
│ ├── helloget.rb
│ ├── hellowithdata.rb
│ ├── hellowithdeps.rb
│ └── latest.rb
├── go.mod
├── go.sum
├── hack/
│ ├── boilerplate.go.txt
│ └── update-codegen.sh
├── kubeless-non-rbac.jsonnet
├── kubeless-openshift.jsonnet
├── kubeless.jsonnet
├── manifests/
│ ├── README.md
│ ├── autoscaling/
│ │ ├── custom-metrics.yaml
│ │ ├── prometheus-operator.yaml
│ │ ├── sample-metrics-app.yaml
│ │ └── sample-prometheus-instance.yaml
│ ├── kinesis/
│ │ └── kinesalite.yaml
│ ├── monitoring/
│ │ ├── grafana-configmap.yaml
│ │ ├── grafana-deployment.yaml
│ │ ├── grafana-job.yaml
│ │ ├── grafana-service.yaml
│ │ └── prometheus.yaml
│ ├── nats/
│ │ └── nats-cluster.yaml
│ └── ui/
│ └── README.md
├── pkg/
│ ├── apis/
│ │ └── kubeless/
│ │ ├── register.go
│ │ └── v1beta1/
│ │ ├── doc.go
│ │ ├── function.go
│ │ ├── register.go
│ │ └── zz_generated.deepcopy.go
│ ├── client/
│ │ ├── clientset/
│ │ │ └── versioned/
│ │ │ ├── clientset.go
│ │ │ ├── doc.go
│ │ │ ├── fake/
│ │ │ │ ├── clientset_generated.go
│ │ │ │ ├── doc.go
│ │ │ │ └── register.go
│ │ │ ├── scheme/
│ │ │ │ ├── doc.go
│ │ │ │ └── register.go
│ │ │ └── typed/
│ │ │ └── kubeless/
│ │ │ └── v1beta1/
│ │ │ ├── doc.go
│ │ │ ├── fake/
│ │ │ │ ├── doc.go
│ │ │ │ ├── fake_function.go
│ │ │ │ └── fake_kubeless_client.go
│ │ │ ├── function.go
│ │ │ ├── generated_expansion.go
│ │ │ └── kubeless_client.go
│ │ ├── informers/
│ │ │ └── externalversions/
│ │ │ ├── factory.go
│ │ │ ├── generic.go
│ │ │ ├── internalinterfaces/
│ │ │ │ └── factory_interfaces.go
│ │ │ └── kubeless/
│ │ │ ├── interface.go
│ │ │ └── v1beta1/
│ │ │ ├── function.go
│ │ │ └── interface.go
│ │ └── listers/
│ │ └── kubeless/
│ │ └── v1beta1/
│ │ ├── expansion_generated.go
│ │ └── function.go
│ ├── controller/
│ │ ├── function_controller.go
│ │ └── function_controller_test.go
│ ├── function-image-builder/
│ │ ├── image_builder.go
│ │ └── layer-builder/
│ │ ├── description.go
│ │ ├── description_test.go
│ │ ├── layer.go
│ │ ├── layer_builder.go
│ │ ├── layer_test.go
│ │ ├── manifest.go
│ │ └── manifest_test.go
│ ├── function-proxy/
│ │ ├── Gopkg.toml
│ │ ├── proxy.go
│ │ └── utils/
│ │ └── proxy-utils.go
│ ├── functions/
│ │ └── params.go
│ ├── langruntime/
│ │ ├── langruntime.go
│ │ ├── langruntime_test.go
│ │ └── langruntimetestutils.go
│ ├── registry/
│ │ ├── registry.go
│ │ └── registry_test.go
│ ├── utils/
│ │ ├── configlocation.go
│ │ ├── exec.go
│ │ ├── exec_test.go
│ │ ├── k8sutil.go
│ │ ├── k8sutil_test.go
│ │ ├── kubelessutil.go
│ │ ├── kubelessutil_test.go
│ │ └── metrics.go
│ └── version/
│ └── version.go
├── script/
│ ├── .validate
│ ├── binary
│ ├── binary-cli
│ ├── binary-controller
│ ├── cluster-up-minikube.sh
│ ├── create_release.sh
│ ├── enable-gcloud.sh
│ ├── find_digest.sh
│ ├── integration-tests
│ ├── libtest.bash
│ ├── pull-or-build-image.sh
│ ├── release_utils.sh
│ ├── start-gke-env.sh
│ ├── start-test-environment.sh
│ ├── upload_release_notes.sh
│ ├── validate-git-marks
│ ├── validate-gofmt
│ ├── validate-lint
│ ├── validate-test
│ └── validate-vet
└── tests/
├── deployment-tests.bats
├── integration-tests-cronjob.bats
├── integration-tests-http.bats
├── integration-tests-kafka.bats
├── integration-tests-kinesis.bats
├── integration-tests-nats.bats
├── integration-tests-prebuilt.bats
└── integration-tests.bats
SYMBOL INDEX (485 symbols across 123 files)
FILE: cmd/function-controller/function-controller.go
constant globalUsage (line 37) | globalUsage = ``
function main (line 79) | func main() {
FILE: cmd/kubeless/autoscale/autoscale.go
function init (line 37) | func init() {
function getHorizontalAutoscaleDefinition (line 47) | func getHorizontalAutoscaleDefinition(name, ns, metric string, min, max ...
FILE: cmd/kubeless/autoscale/autoscaleCreate.go
function init (line 77) | func init() {
FILE: cmd/kubeless/autoscale/autoscaleList.go
function init (line 57) | func init() {
function doAutoscaleList (line 61) | func doAutoscaleList(w io.Writer, client kubernetes.Interface, ns, outpu...
function printAutoscale (line 73) | func printAutoscale(w io.Writer, ass []v2beta1.HorizontalPodAutoscaler, ...
FILE: cmd/kubeless/autoscale/autoscaleList_test.go
function listAutoscaleOutput (line 16) | func listAutoscaleOutput(t *testing.T, client kubernetes.Interface, ns, ...
function TestAutoscaleList (line 26) | func TestAutoscaleList(t *testing.T) {
FILE: cmd/kubeless/autoscale/autoscale_test.go
function TestGetHorizontalAutoscaleDefinition (line 11) | func TestGetHorizontalAutoscaleDefinition(t *testing.T) {
FILE: cmd/kubeless/function/call.go
function init (line 117) | func init() {
FILE: cmd/kubeless/function/delete.go
function init (line 55) | func init() {
FILE: cmd/kubeless/function/deploy.go
function init (line 284) | func init() {
FILE: cmd/kubeless/function/describe.go
function init (line 67) | func init() {
function print (line 72) | func print(f kubelessApi.Function, name, output string) error {
FILE: cmd/kubeless/function/function.go
function init (line 44) | func init() {
function getKV (line 55) | func getKV(input string) (string, string) {
function parseLabel (line 69) | func parseLabel(labels []string) map[string]string {
function parseEnv (line 78) | func parseEnv(envs []string) []v1.EnvVar {
function parseResource (line 90) | func parseResource(in string) (resource.Quantity, error) {
function parseNodeSelectors (line 103) | func parseNodeSelectors(nodeSelectors []string) map[string]string {
function getFunctionDescription (line 112) | func getFunctionDescription(funcName, ns, handler, file, deps, runtime, ...
function getDeploymentStatus (line 269) | func getDeploymentStatus(cli kubernetes.Interface, funcName, ns string) ...
function getFunctions (line 283) | func getFunctions(kubelessClient versioned.Interface, namespace, functio...
FILE: cmd/kubeless/function/function_test.go
function TestParseLabel (line 43) | func TestParseLabel(t *testing.T) {
function TestParseEnv (line 60) | func TestParseEnv(t *testing.T) {
function TestParseNodeSelectors (line 96) | func TestParseNodeSelectors(t *testing.T) {
function TestGetFunctionDescription (line 111) | func TestGetFunctionDescription(t *testing.T) {
function getSha256 (line 595) | func getSha256(bytes []byte) (string, error) {
FILE: cmd/kubeless/function/list.go
function init (line 70) | func init() {
function doList (line 75) | func doList(w io.Writer, kubelessClient versioned.Interface, apiV1Client...
function parseDeps (line 97) | func parseDeps(deps, runtime string) (res string, err error) {
function printFunctions (line 120) | func printFunctions(w io.Writer, functions []*kubelessApi.Function, cli ...
FILE: cmd/kubeless/function/list_test.go
function listOutput (line 37) | func listOutput(t *testing.T, client versioned.Interface, apiV1Client ku...
function TestList (line 47) | func TestList(t *testing.T) {
FILE: cmd/kubeless/function/logs.go
function init (line 77) | func init() {
FILE: cmd/kubeless/function/top.go
function init (line 70) | func init() {
function doTop (line 76) | func doTop(w io.Writer, kubelessClient versioned.Interface, apiV1Client ...
function printTop (line 110) | func printTop(w io.Writer, metrics []*utils.Metric, cli kubernetes.Inter...
FILE: cmd/kubeless/function/top_test.go
type testMetricsHandler (line 41) | type testMetricsHandler struct
method GetRawMetrics (line 45) | func (h *testMetricsHandler) GetRawMetrics(apiClient kubernetes.Interf...
function topOutput (line 58) | func topOutput(t *testing.T, client versioned.Interface, apiV1Client kub...
function TestTop (line 68) | func TestTop(t *testing.T) {
FILE: cmd/kubeless/function/update.go
function init (line 225) | func init() {
FILE: cmd/kubeless/kubeless.go
function newRootCmd (line 35) | func newRootCmd() *cobra.Command {
function main (line 46) | func main() {
FILE: cmd/kubeless/topic/topic.go
function init (line 33) | func init() {
FILE: cmd/kubeless/topic/topicCreate.go
function createTopic (line 59) | func createTopic(conf *rest.Config, clientset kubernetes.Interface, ctlN...
function execCommand (line 73) | func execCommand(conf *rest.Config, k8sClientSet kubernetes.Interface, c...
FILE: cmd/kubeless/topic/topicDelete.go
function deleteTopic (line 58) | func deleteTopic(conf *rest.Config, clientset kubernetes.Interface, ctlN...
FILE: cmd/kubeless/topic/topicList.go
function listTopic (line 54) | func listTopic(conf *rest.Config, clientset kubernetes.Interface, ctlNam...
FILE: cmd/kubeless/topic/topicPublish.go
function publishTopic (line 65) | func publishTopic(conf *rest.Config, clientset kubernetes.Interface, nam...
function init (line 116) | func init() {
FILE: cmd/kubeless/trigger/cronjob/create.go
function init (line 143) | func init() {
FILE: cmd/kubeless/trigger/cronjob/cronjob_trigger.go
function init (line 38) | func init() {
function parsePayload (line 45) | func parsePayload(content string, file string) (interface{}, error) {
function getPayloadRawContent (line 58) | func getPayloadRawContent(file string) (string, error) {
function parsePayloadContent (line 77) | func parsePayloadContent(raw string) interface{} {
FILE: cmd/kubeless/trigger/cronjob/delete.go
function init (line 58) | func init() {
FILE: cmd/kubeless/trigger/cronjob/list.go
function init (line 57) | func init() {
function doList (line 61) | func doList(w io.Writer, kubelessClient versioned.Interface, ns string) ...
FILE: cmd/kubeless/trigger/cronjob/update.go
function init (line 135) | func init() {
FILE: cmd/kubeless/trigger/http/create.go
function init (line 175) | func init() {
FILE: cmd/kubeless/trigger/http/delete.go
function init (line 59) | func init() {
FILE: cmd/kubeless/trigger/http/http_trigger.go
function init (line 33) | func init() {
FILE: cmd/kubeless/trigger/http/list.go
function init (line 57) | func init() {
function doList (line 61) | func doList(w io.Writer, kubelessClient versioned.Interface, ns string) ...
FILE: cmd/kubeless/trigger/http/update.go
function init (line 149) | func init() {
FILE: cmd/kubeless/trigger/kafka/create.go
function init (line 113) | func init() {
FILE: cmd/kubeless/trigger/kafka/delete.go
function init (line 58) | func init() {
FILE: cmd/kubeless/trigger/kafka/kafka_trigger.go
function init (line 33) | func init() {
FILE: cmd/kubeless/trigger/kafka/list.go
function init (line 59) | func init() {
function doList (line 63) | func doList(w io.Writer, kubelessClient versioned.Interface, ns string) ...
FILE: cmd/kubeless/trigger/kafka/update.go
function init (line 107) | func init() {
FILE: cmd/kubeless/trigger/kinesis/create.go
function init (line 153) | func init() {
FILE: cmd/kubeless/trigger/kinesis/delete.go
function init (line 59) | func init() {
FILE: cmd/kubeless/trigger/kinesis/kinesis_trigger.go
function init (line 33) | func init() {
FILE: cmd/kubeless/trigger/kinesis/list.go
function init (line 59) | func init() {
function doList (line 63) | func doList(w io.Writer, kubelessClient versioned.Interface, ns string) ...
FILE: cmd/kubeless/trigger/kinesis/publish.go
function init (line 117) | func init() {
FILE: cmd/kubeless/trigger/kinesis/stream_create.go
function init (line 99) | func init() {
FILE: cmd/kubeless/trigger/kinesis/update.go
function init (line 130) | func init() {
FILE: cmd/kubeless/trigger/nats/create.go
function init (line 114) | func init() {
FILE: cmd/kubeless/trigger/nats/delete.go
function init (line 59) | func init() {
FILE: cmd/kubeless/trigger/nats/list.go
function init (line 59) | func init() {
function doList (line 63) | func doList(w io.Writer, kubelessClient versioned.Interface, ns string) ...
FILE: cmd/kubeless/trigger/nats/nats_trigger.go
function init (line 33) | func init() {
FILE: cmd/kubeless/trigger/nats/publish.go
function publishTopic (line 53) | func publishTopic(topic, message, url string) error {
function init (line 68) | func init() {
FILE: cmd/kubeless/trigger/nats/update.go
function init (line 107) | func init() {
FILE: cmd/kubeless/trigger/trigger.go
function init (line 38) | func init() {
FILE: docker/event-sources/kubernetes/events.py
function pods (line 29) | def pods():
function namespaces (line 39) | def namespaces():
function services (line 49) | def services():
function deployments (line 60) | def deployments():
function replicasets (line 70) | def replicasets():
FILE: examples/dotnetcore/dependency-yaml.cs
class module (line 5) | public class module
method handler (line 7) | public string handler(Event k8Event, Context k8Context)
class Person (line 20) | public class Person
FILE: examples/dotnetcore/fibonacci.cs
class module (line 4) | public class module
method handler (line 6) | public int handler(Event k8Event, Context k8Context)
method fibonacci (line 13) | public int fibonacci(int n)
FILE: examples/dotnetcore/helloget.cs
class module (line 4) | public class module
method handler (line 6) | public string handler(Event k8Event, Context k8Context)
FILE: examples/dotnetcore/hellowithdata.cs
class module (line 4) | public class module
method handler (line 6) | public object handler(Event k8Event, Context k8Context)
FILE: examples/golang/helloget.go
function Foo (line 8) | func Foo(event functions.Event, context functions.Context) (string, erro...
FILE: examples/golang/hellowithdata.go
function Handler (line 10) | func Handler(event functions.Event, context functions.Context) (string, ...
FILE: examples/golang/hellowithdeps.go
function Hello (line 9) | func Hello(event functions.Event, context functions.Context) (string, er...
FILE: examples/java/HelloGet.java
class Foo (line 6) | public class Foo {
method foo (line 7) | public String foo(io.kubeless.Event event, io.kubeless.Context context) {
FILE: examples/java/HelloWithData.java
class Foo (line 6) | public class Foo {
method foo (line 7) | public String foo(io.kubeless.Event event, io.kubeless.Context context) {
FILE: examples/java/HelloWithDeps.java
class Hello (line 8) | public class Hello {
method sayHello (line 9) | public String sayHello(io.kubeless.Event event, io.kubeless.Context co...
FILE: examples/jvm/java/src/main/java/io/ino/Handler.java
class Handler (line 3) | public class Handler {
method sayHello (line 4) | public String sayHello(io.kubeless.Event event, io.kubeless.Context co...
FILE: examples/nodejs/hellostream.js
function fromString (line 4) | function fromString(string) {
FILE: examples/php/helloget.php
function foo (line 3) | function foo($event, $context) {
FILE: examples/php/hellowithdata.php
function foo (line 3) | function foo($event, $context) {
FILE: examples/php/hellowithdeps.php
function foo (line 8) | function foo($event, $context) {
FILE: examples/python/helloget.py
function foo (line 1) | def foo(event, context):
FILE: examples/python/hellowithdata.py
function handler (line 1) | def handler(event, context):
FILE: examples/python/hellowithdepshelper.py
function foo (line 4) | def foo(event, context):
FILE: examples/ruby/helloget.rb
function foo (line 1) | def foo(event, context)
FILE: examples/ruby/hellowithdata.rb
function handler (line 1) | def handler(event, context)
FILE: examples/ruby/hellowithdeps.rb
function foo (line 3) | def foo(event, context)
FILE: examples/ruby/latest.rb
function handler (line 2) | def handler(event, context)
FILE: pkg/apis/kubeless/register.go
constant GroupName (line 5) | GroupName = "kubeless.io"
FILE: pkg/apis/kubeless/v1beta1/function.go
type Function (line 30) | type Function struct
type FunctionSpec (line 37) | type FunctionSpec struct
type FunctionList (line 53) | type FunctionList struct
FILE: pkg/apis/kubeless/v1beta1/register.go
function Kind (line 15) | func Kind(kind string) schema.GroupKind {
function Resource (line 20) | func Resource(resource string) schema.GroupResource {
function addKnownTypes (line 33) | func addKnownTypes(scheme *runtime.Scheme) error {
FILE: pkg/apis/kubeless/v1beta1/zz_generated.deepcopy.go
method DeepCopyInto (line 28) | func (in *Function) DeepCopyInto(out *Function) {
method DeepCopy (line 37) | func (in *Function) DeepCopy() *Function {
method DeepCopyObject (line 47) | func (in *Function) DeepCopyObject() runtime.Object {
method DeepCopyInto (line 55) | func (in *FunctionList) DeepCopyInto(out *FunctionList) {
method DeepCopy (line 75) | func (in *FunctionList) DeepCopy() *FunctionList {
method DeepCopyObject (line 85) | func (in *FunctionList) DeepCopyObject() runtime.Object {
method DeepCopyInto (line 93) | func (in *FunctionSpec) DeepCopyInto(out *FunctionSpec) {
method DeepCopy (line 102) | func (in *FunctionSpec) DeepCopy() *FunctionSpec {
FILE: pkg/client/clientset/versioned/clientset.go
type Interface (line 26) | type Interface interface
type Clientset (line 35) | type Clientset struct
method KubelessV1beta1 (line 41) | func (c *Clientset) KubelessV1beta1() kubelessv1beta1.KubelessV1beta1I...
method Kubeless (line 47) | func (c *Clientset) Kubeless() kubelessv1beta1.KubelessV1beta1Interface {
method Discovery (line 52) | func (c *Clientset) Discovery() discovery.DiscoveryInterface {
function NewForConfig (line 60) | func NewForConfig(c *rest.Config) (*Clientset, error) {
function NewForConfigOrDie (line 82) | func NewForConfigOrDie(c *rest.Config) *Clientset {
function New (line 91) | func New(c rest.Interface) *Clientset {
FILE: pkg/client/clientset/versioned/fake/clientset_generated.go
function NewSimpleClientset (line 33) | func NewSimpleClientset(objects ...runtime.Object) *Clientset {
type Clientset (line 51) | type Clientset struct
method Discovery (line 56) | func (c *Clientset) Discovery() discovery.DiscoveryInterface {
method KubelessV1beta1 (line 63) | func (c *Clientset) KubelessV1beta1() kubelessv1beta1.KubelessV1beta1I...
method Kubeless (line 68) | func (c *Clientset) Kubeless() kubelessv1beta1.KubelessV1beta1Interface {
FILE: pkg/client/clientset/versioned/fake/register.go
function init (line 30) | func init() {
function AddToScheme (line 49) | func AddToScheme(scheme *runtime.Scheme) {
FILE: pkg/client/clientset/versioned/scheme/register.go
function init (line 30) | func init() {
function AddToScheme (line 49) | func AddToScheme(scheme *runtime.Scheme) {
FILE: pkg/client/clientset/versioned/typed/kubeless/v1beta1/fake/fake_function.go
type FakeFunctions (line 29) | type FakeFunctions struct
method Get (line 39) | func (c *FakeFunctions) Get(name string, options v1.GetOptions) (resul...
method List (line 50) | func (c *FakeFunctions) List(opts v1.ListOptions) (result *v1beta1.Fun...
method Watch (line 72) | func (c *FakeFunctions) Watch(opts v1.ListOptions) (watch.Interface, e...
method Create (line 79) | func (c *FakeFunctions) Create(function *v1beta1.Function) (result *v1...
method Update (line 90) | func (c *FakeFunctions) Update(function *v1beta1.Function) (result *v1...
method Delete (line 101) | func (c *FakeFunctions) Delete(name string, options *v1.DeleteOptions)...
method DeleteCollection (line 109) | func (c *FakeFunctions) DeleteCollection(options *v1.DeleteOptions, li...
method Patch (line 117) | func (c *FakeFunctions) Patch(name string, pt types.PatchType, data []...
FILE: pkg/client/clientset/versioned/typed/kubeless/v1beta1/fake/fake_kubeless_client.go
type FakeKubelessV1beta1 (line 24) | type FakeKubelessV1beta1 struct
method Functions (line 28) | func (c *FakeKubelessV1beta1) Functions(namespace string) v1beta1.Func...
method RESTClient (line 34) | func (c *FakeKubelessV1beta1) RESTClient() rest.Interface {
FILE: pkg/client/clientset/versioned/typed/kubeless/v1beta1/function.go
type FunctionsGetter (line 29) | type FunctionsGetter interface
type FunctionInterface (line 34) | type FunctionInterface interface
type functions (line 47) | type functions struct
method Get (line 61) | func (c *functions) Get(name string, options v1.GetOptions) (result *v...
method List (line 74) | func (c *functions) List(opts v1.ListOptions) (result *v1beta1.Functio...
method Watch (line 86) | func (c *functions) Watch(opts v1.ListOptions) (watch.Interface, error) {
method Create (line 96) | func (c *functions) Create(function *v1beta1.Function) (result *v1beta...
method Update (line 108) | func (c *functions) Update(function *v1beta1.Function) (result *v1beta...
method Delete (line 121) | func (c *functions) Delete(name string, options *v1.DeleteOptions) err...
method DeleteCollection (line 132) | func (c *functions) DeleteCollection(options *v1.DeleteOptions, listOp...
method Patch (line 143) | func (c *functions) Patch(name string, pt types.PatchType, data []byte...
function newFunctions (line 53) | func newFunctions(c *KubelessV1beta1Client, namespace string) *functions {
FILE: pkg/client/clientset/versioned/typed/kubeless/v1beta1/generated_expansion.go
type FunctionExpansion (line 18) | type FunctionExpansion interface
FILE: pkg/client/clientset/versioned/typed/kubeless/v1beta1/kubeless_client.go
type KubelessV1beta1Interface (line 25) | type KubelessV1beta1Interface interface
type KubelessV1beta1Client (line 31) | type KubelessV1beta1Client struct
method Functions (line 35) | func (c *KubelessV1beta1Client) Functions(namespace string) FunctionIn...
method RESTClient (line 82) | func (c *KubelessV1beta1Client) RESTClient() rest.Interface {
function NewForConfig (line 40) | func NewForConfig(c *rest.Config) (*KubelessV1beta1Client, error) {
function NewForConfigOrDie (line 54) | func NewForConfigOrDie(c *rest.Config) *KubelessV1beta1Client {
function New (line 63) | func New(c rest.Interface) *KubelessV1beta1Client {
function setConfigDefaults (line 67) | func setConfigDefaults(config *rest.Config) error {
FILE: pkg/client/informers/externalversions/factory.go
type sharedInformerFactory (line 35) | type sharedInformerFactory struct
method Start (line 68) | func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
method WaitForCacheSync (line 81) | func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{...
method InformerFor (line 104) | func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFun...
method Kubeless (line 129) | func (f *sharedInformerFactory) Kubeless() kubeless.Interface {
function NewSharedInformerFactory (line 49) | func NewSharedInformerFactory(client versioned.Interface, defaultResync ...
function NewFilteredSharedInformerFactory (line 56) | func NewFilteredSharedInformerFactory(client versioned.Interface, defaul...
type SharedInformerFactory (line 121) | type SharedInformerFactory interface
FILE: pkg/client/informers/externalversions/generic.go
type GenericInformer (line 31) | type GenericInformer interface
type genericInformer (line 36) | type genericInformer struct
method Informer (line 42) | func (f *genericInformer) Informer() cache.SharedIndexInformer {
method Lister (line 47) | func (f *genericInformer) Lister() cache.GenericLister {
method ForResource (line 53) | func (f *sharedInformerFactory) ForResource(resource schema.GroupVersion...
FILE: pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go
type NewInformerFunc (line 30) | type NewInformerFunc
type SharedInformerFactory (line 33) | type SharedInformerFactory interface
type TweakListOptionsFunc (line 38) | type TweakListOptionsFunc
FILE: pkg/client/informers/externalversions/kubeless/interface.go
type Interface (line 27) | type Interface interface
type group (line 32) | type group struct
method V1beta1 (line 44) | func (g *group) V1beta1() v1beta1.Interface {
function New (line 39) | func New(f internalinterfaces.SharedInformerFactory, namespace string, t...
FILE: pkg/client/informers/externalversions/kubeless/v1beta1/function.go
type FunctionInformer (line 36) | type FunctionInformer interface
type functionInformer (line 41) | type functionInformer struct
method defaultInformer (line 79) | func (f *functionInformer) defaultInformer(client versioned.Interface,...
method Informer (line 83) | func (f *functionInformer) Informer() cache.SharedIndexInformer {
method Lister (line 87) | func (f *functionInformer) Lister() v1beta1.FunctionLister {
function NewFunctionInformer (line 50) | func NewFunctionInformer(client versioned.Interface, namespace string, r...
function NewFilteredFunctionInformer (line 57) | func NewFilteredFunctionInformer(client versioned.Interface, namespace s...
FILE: pkg/client/informers/externalversions/kubeless/v1beta1/interface.go
type Interface (line 26) | type Interface interface
type version (line 31) | type version struct
method Functions (line 43) | func (v *version) Functions() FunctionInformer {
function New (line 38) | func New(f internalinterfaces.SharedInformerFactory, namespace string, t...
FILE: pkg/client/listers/kubeless/v1beta1/expansion_generated.go
type FunctionListerExpansion (line 23) | type FunctionListerExpansion interface
type FunctionNamespaceListerExpansion (line 27) | type FunctionNamespaceListerExpansion interface
FILE: pkg/client/listers/kubeless/v1beta1/function.go
type FunctionLister (line 29) | type FunctionLister interface
type functionLister (line 38) | type functionLister struct
method List (line 48) | func (s *functionLister) List(selector labels.Selector) (ret []*v1beta...
method Functions (line 56) | func (s *functionLister) Functions(namespace string) FunctionNamespace...
function NewFunctionLister (line 43) | func NewFunctionLister(indexer cache.Indexer) FunctionLister {
type FunctionNamespaceLister (line 61) | type FunctionNamespaceLister interface
type functionNamespaceLister (line 71) | type functionNamespaceLister struct
method List (line 77) | func (s functionNamespaceLister) List(selector labels.Selector) (ret [...
method Get (line 85) | func (s functionNamespaceLister) Get(name string) (*v1beta1.Function, ...
FILE: pkg/controller/function_controller.go
constant maxRetries (line 49) | maxRetries = 5
constant funcKind (line 50) | funcKind = "Function"
constant funcAPIVersion (line 51) | funcAPIVersion = "kubeless.io/v1beta1"
constant functionFinalizer (line 52) | functionFinalizer = "kubeless.io/function"
type FunctionController (line 56) | type FunctionController struct
method Run (line 133) | func (c *FunctionController) Run(stopCh <-chan struct{}) {
method HasSynced (line 152) | func (c *FunctionController) HasSynced() bool {
method LastSyncResourceVersion (line 157) | func (c *FunctionController) LastSyncResourceVersion() string {
method runWorker (line 161) | func (c *FunctionController) runWorker() {
method processNextItem (line 167) | func (c *FunctionController) processNextItem() bool {
method processItem (line 191) | func (c *FunctionController) processItem(key string) error {
method startImageBuildJob (line 258) | func (c *FunctionController) startImageBuildJob(funcObj *kubelessApi.F...
method ensureK8sResources (line 297) | func (c *FunctionController) ensureK8sResources(funcObj *kubelessApi.F...
method deleteAutoscale (line 386) | func (c *FunctionController) deleteAutoscale(ns, name string) error {
method deleteK8sResources (line 403) | func (c *FunctionController) deleteK8sResources(ns, name string) error {
type Config (line 70) | type Config struct
function NewFunctionController (line 76) | func NewFunctionController(cfg Config, smclient *monitoringv1alpha1.Moni...
function functionObjChanged (line 440) | func functionObjChanged(oldFunctionObj, newFunctionObj *kubelessApi.Func...
FILE: pkg/controller/function_controller_test.go
function findAction (line 20) | func findAction(fake *fake.Clientset, verb, resource string) ktesting.Ac...
function hasAction (line 29) | func hasAction(fake *fake.Clientset, verb, resource string) bool {
function TestDeleteK8sResources (line 33) | func TestDeleteK8sResources(t *testing.T) {
function TestEnsureK8sResourcesWithDeploymentDefinitionFromConfigMap (line 114) | func TestEnsureK8sResourcesWithDeploymentDefinitionFromConfigMap(t *test...
function TestEnsureK8sResourcesWithDeploymentDefinitionFromConfigMapUnknownKey (line 171) | func TestEnsureK8sResourcesWithDeploymentDefinitionFromConfigMapUnknownK...
function TestEnsureK8sResourcesWithLivenessProbeFromConfigMap (line 192) | func TestEnsureK8sResourcesWithLivenessProbeFromConfigMap(t *testing.T) {
function testFunc (line 246) | func testFunc() *kubelessApi.Function {
function testRuntimeImages (line 294) | func testRuntimeImages() string {
function testController (line 318) | func testController(clientset kubernetes.Interface, namespace string, co...
FILE: pkg/function-image-builder/image_builder.go
function init (line 33) | func init() {
function runCommand (line 42) | func runCommand(command string, args []string) error {
function skopeoCopy (line 65) | func skopeoCopy(src, dst, srcCreds, dstCreds string, insecure bool) error {
function newRootCmd (line 157) | func newRootCmd() *cobra.Command {
function main (line 168) | func main() {
FILE: pkg/function-image-builder/layer-builder/description.go
type Config (line 29) | type Config struct
type HistoryEntry (line 51) | type HistoryEntry struct
type Rootfs (line 59) | type Rootfs struct
type Description (line 65) | type Description struct
method New (line 78) | func (d *Description) New(descriptionFile io.Reader) error {
method AddLayer (line 87) | func (d *Description) AddLayer(newLayer *Layer) {
method Content (line 104) | func (d *Description) Content() ([]byte, error) {
method ToLayer (line 109) | func (d *Description) ToLayer() (*Layer, error) {
FILE: pkg/function-image-builder/layer-builder/description_test.go
function TestNewDescription (line 24) | func TestNewDescription(t *testing.T) {
function TestAddLayerDescription (line 33) | func TestAddLayerDescription(t *testing.T) {
function TestDescriptionToLayer (line 55) | func TestDescriptionToLayer(t *testing.T) {
FILE: pkg/function-image-builder/layer-builder/layer.go
type Layer (line 27) | type Layer struct
method New (line 33) | func (f *Layer) New(layerFile *os.File) error {
FILE: pkg/function-image-builder/layer-builder/layer_builder.go
function copyReader (line 31) | func copyReader(src io.Reader, dst string) error {
function copyFile (line 49) | func copyFile(src, dst string) error {
function getLayer (line 59) | func getLayer(file string) (*Layer, error) {
function saveNewDescription (line 73) | func saveNewDescription(content []byte, dir, contentChecksum string) err...
function updateDescription (line 78) | func updateDescription(descriptionDir string, descriptionFile *os.File, ...
function AddTarToLayer (line 92) | func AddTarToLayer(imageDir, tarFile string) error {
FILE: pkg/function-image-builder/layer-builder/layer_test.go
function TestNewLayer (line 25) | func TestNewLayer(t *testing.T) {
FILE: pkg/function-image-builder/layer-builder/manifest.go
type layer (line 26) | type layer struct
type Manifest (line 33) | type Manifest struct
method New (line 41) | func (m *Manifest) New(manifestFile io.Reader) error {
method UpdateConfig (line 54) | func (m *Manifest) UpdateConfig(newConfig *Layer) {
method AddLayer (line 60) | func (m *Manifest) AddLayer(newLayer *Layer) {
FILE: pkg/function-image-builder/layer-builder/manifest_test.go
function TestNewManifest (line 24) | func TestNewManifest(t *testing.T) {
function TestAddNewLayer (line 42) | func TestAddNewLayer(t *testing.T) {
function TestUpdateConfig (line 61) | func TestUpdateConfig(t *testing.T) {
FILE: pkg/function-proxy/proxy.go
function copyHeaders (line 32) | func copyHeaders(dst, src http.Header) {
function handle (line 40) | func handle(ctx context.Context, w http.ResponseWriter, r *http.Request)...
function handler (line 55) | func handler(w http.ResponseWriter, r *http.Request) {
function health (line 59) | func health(w http.ResponseWriter, r *http.Request) {
function startNativeDaemon (line 72) | func startNativeDaemon() {
function main (line 83) | func main() {
FILE: pkg/function-proxy/utils/proxy-utils.go
function PromHTTPHandler (line 55) | func PromHTTPHandler() http.Handler {
function init (line 59) | func init() {
type loggingResponseWriter (line 82) | type loggingResponseWriter struct
method WriteHeader (line 91) | func (lrw *loggingResponseWriter) WriteHeader(code int) {
function newLoggingResponseWriter (line 87) | func newLoggingResponseWriter(w http.ResponseWriter) *loggingResponseWri...
function logReq (line 96) | func logReq(handler http.Handler) http.Handler {
function copyHeaders (line 111) | func copyHeaders(dst, src http.Header) {
type Handle (line 120) | type Handle
function Handler (line 124) | func Handler(w http.ResponseWriter, r *http.Request, h Handle) {
function NewServer (line 161) | func NewServer(mux *http.ServeMux) *http.Server {
function GracefulShutdown (line 167) | func GracefulShutdown(server *http.Server) {
FILE: pkg/functions/params.go
type Extension (line 25) | type Extension struct
type Event (line 32) | type Event struct
type Context (line 42) | type Context struct
FILE: pkg/langruntime/langruntime.go
constant PhaseInstallation (line 19) | PhaseInstallation = "installation"
constant PhaseCompilation (line 21) | PhaseCompilation = "compilation"
constant PhaseRuntime (line 23) | PhaseRuntime = "runtime"
type Langruntimes (line 27) | type Langruntimes struct
method ReadConfigMap (line 80) | func (l *Langruntimes) ReadConfigMap() {
method GetRuntimes (line 90) | func (l *Langruntimes) GetRuntimes() []string {
method IsValidRuntime (line 101) | func (l *Langruntimes) IsValidRuntime(runtime string) bool {
method getAvailableRuntimesPerTrigger (line 110) | func (l *Langruntimes) getAvailableRuntimesPerTrigger(imageType string...
method getVersionFromRuntime (line 123) | func (l *Langruntimes) getVersionFromRuntime(runtime string) string {
method GetRuntimeInfo (line 129) | func (l *Langruntimes) GetRuntimeInfo(runtime string) (RuntimeInfo, er...
method GetLivenessProbeInfo (line 141) | func (l *Langruntimes) GetLivenessProbeInfo(runtime string, port int) ...
method findRuntimeVersion (line 165) | func (l *Langruntimes) findRuntimeVersion(runtimeWithVersion string) (...
method findImage (line 180) | func (l *Langruntimes) findImage(phase string, runtime RuntimeVersion)...
method GetFunctionImage (line 190) | func (l *Langruntimes) GetFunctionImage(runtime string) (string, error) {
method GetImageSecrets (line 214) | func (l *Langruntimes) GetImageSecrets(runtime string) ([]v1.LocalObje...
method GetInitContainerSecrets (line 241) | func (l *Langruntimes) GetInitContainerSecrets(runtime, name string) (...
method GetBuildContainer (line 283) | func (l *Langruntimes) GetBuildContainer(runtime, depsChecksum string,...
method UpdateDeployment (line 336) | func (l *Langruntimes) UpdateDeployment(dpm *appsv1.Deployment, volPat...
method GetCompilationContainer (line 359) | func (l *Langruntimes) GetCompilationContainer(runtime, funcName strin...
type Image (line 33) | type Image struct
type Secret (line 42) | type Secret struct
type RuntimeVersion (line 47) | type RuntimeVersion struct
type ImageSecret (line 55) | type ImageSecret struct
type RuntimeInfo (line 61) | type RuntimeInfo struct
function New (line 70) | func New(config *v1.ConfigMap) *Langruntimes {
function appendToCommand (line 267) | func appendToCommand(orig string, command ...string) string {
function parseEnv (line 274) | func parseEnv(env map[string]string) []v1.EnvVar {
function name2phase (line 391) | func name2phase(name string) string {
FILE: pkg/langruntime/langruntime_test.go
function TestMain (line 17) | func TestMain(m *testing.M) {
function check (line 22) | func check(clientset *fake.Clientset, lr *Langruntimes, runtime, fname s...
function TestGetFunctionFileNames (line 36) | func TestGetFunctionFileNames(t *testing.T) {
function TestGetFunctionImage (line 44) | func TestGetFunctionImage(t *testing.T) {
function TestGetLivenessProbe (line 73) | func TestGetLivenessProbe(t *testing.T) {
function TestGetRuntimes (line 93) | func TestGetRuntimes(t *testing.T) {
function TestGetBuildContainer (line 104) | func TestGetBuildContainer(t *testing.T) {
function TestGetBuildContainerWithBundledDeps (line 140) | func TestGetBuildContainerWithBundledDeps(t *testing.T) {
FILE: pkg/langruntime/langruntimetestutils.go
function AddFakeConfig (line 12) | func AddFakeConfig(clientset *fake.Clientset) {
function SetupLangRuntime (line 66) | func SetupLangRuntime(clientset *fake.Clientset) *Langruntimes {
FILE: pkg/registry/registry.go
type Credentials (line 32) | type Credentials struct
type Registry (line 40) | type Registry struct
method getTags (line 87) | func (r *Registry) getTags(body []byte) ([]string, error) {
method tagURL (line 113) | func (r *Registry) tagURL(img string) (string, error) {
method doRequest (line 183) | func (r *Registry) doRequest(url string) ([]byte, error) {
method ImageExists (line 216) | func (r *Registry) ImageExists(id, tag string) (bool, error) {
type tagv1 (line 46) | type tagv1 struct
type tagListV2 (line 51) | type tagListV2 struct
type dockerCfg (line 56) | type dockerCfg struct
function New (line 61) | func New(config v1.Secret) (*Registry, error) {
function findProperty (line 125) | func findProperty(src, property string) (string, error) {
type authResponse (line 134) | type authResponse struct
function doRequestWithAuth (line 139) | func doRequestWithAuth(authInfo, url string, client *http.Client) ([]byt...
FILE: pkg/registry/registry_test.go
function TestNew (line 10) | func TestNew(t *testing.T) {
function TestTagURLV1 (line 34) | func TestTagURLV1(t *testing.T) {
function TestTagURLV2 (line 48) | func TestTagURLV2(t *testing.T) {
function TestGetTagsV1 (line 62) | func TestGetTagsV1(t *testing.T) {
function TestGetTagsV2 (line 78) | func TestGetTagsV2(t *testing.T) {
FILE: pkg/utils/configlocation.go
type ConfigLocation (line 4) | type ConfigLocation struct
FILE: pkg/utils/exec.go
constant stdinChannel (line 19) | stdinChannel = 0
constant stdoutChannel (line 20) | stdoutChannel = 1
constant stderrChannel (line 21) | stderrChannel = 2
constant errChannel (line 22) | errChannel = 3
type Cmd (line 26) | type Cmd struct
method RoundTripCallback (line 35) | func (c *Cmd) RoundTripCallback(conn *websocket.Conn) (*http.Response,...
type RoundTripCallback (line 114) | type RoundTripCallback
type WebsocketRoundTripper (line 118) | type WebsocketRoundTripper struct
method RoundTrip (line 124) | func (d *WebsocketRoundTripper) RoundTrip(r *http.Request) (*http.Resp...
function ExecRoundTripper (line 149) | func ExecRoundTripper(conf *rest.Config, f RoundTripCallback) (http.Roun...
function Exec (line 164) | func Exec(client corev1.CoreV1Interface, pod, namespace string, opts v1....
FILE: pkg/utils/exec_test.go
function TestExecURL (line 11) | func TestExecURL(t *testing.T) {
FILE: pkg/utils/k8sutil.go
constant defaultTimeout (line 53) | defaultTimeout = "180"
function GetClient (line 57) | func GetClient() kubernetes.Interface {
function BuildOutOfClusterConfig (line 72) | func BuildOutOfClusterConfig() (*rest.Config, error) {
function GetClientOutOfCluster (line 96) | func GetClientOutOfCluster() kubernetes.Interface {
function GetAPIExtensionsClientOutOfCluster (line 111) | func GetAPIExtensionsClientOutOfCluster() clientsetAPIExtensions.Interfa...
function GetAPIExtensionsClientInCluster (line 124) | func GetAPIExtensionsClientInCluster() clientsetAPIExtensions.Interface {
function GetFunctionClientInCluster (line 138) | func GetFunctionClientInCluster() (versioned.Interface, error) {
function GetKubelessClientOutCluster (line 153) | func GetKubelessClientOutCluster() (versioned.Interface, error) {
function GetDefaultNamespace (line 167) | func GetDefaultNamespace() string {
function GetFunction (line 179) | func GetFunction(funcName, ns string) (kubelessApi.Function, error) {
function CreateFunctionCustomResource (line 198) | func CreateFunctionCustomResource(kubelessClient versioned.Interface, f ...
function UpdateFunctionCustomResource (line 207) | func UpdateFunctionCustomResource(kubelessClient versioned.Interface, f ...
function PatchFunctionCustomResource (line 213) | func PatchFunctionCustomResource(kubelessClient versioned.Interface, f *...
function DeleteFunctionCustomResource (line 223) | func DeleteFunctionCustomResource(kubelessClient versioned.Interface, fu...
function GetFunctionCustomResource (line 233) | func GetFunctionCustomResource(kubelessClient versioned.Interface, funcN...
function GetPodsByLabel (line 244) | func GetPodsByLabel(c kubernetes.Interface, ns, k, v string) (*v1.PodLis...
function GetReadyPod (line 256) | func GetReadyPod(pods *v1.PodList) (v1.Pod, error) {
function GetLocalHostname (line 273) | func GetLocalHostname(config *rest.Config, funcName string) (string, err...
function doRESTReq (line 283) | func doRESTReq(restIface rest.Interface, groupVersion, verb, resource, e...
function CreateAutoscale (line 320) | func CreateAutoscale(client kubernetes.Interface, hpa v2beta1.Horizontal...
function UpdateAutoscale (line 326) | func UpdateAutoscale(client kubernetes.Interface, hpa v2beta1.Horizontal...
function DeleteAutoscale (line 332) | func DeleteAutoscale(client kubernetes.Interface, name, ns string) error {
function DeleteServiceMonitor (line 341) | func DeleteServiceMonitor(smclient monitoringv1alpha1.MonitoringV1alpha1...
function initializeEmptyMapsInDeployment (line 352) | func initializeEmptyMapsInDeployment(deployment *appsv1.Deployment) {
function MergeDeployments (line 374) | func MergeDeployments(destinationDeployment *appsv1.Deployment, sourceDe...
function FunctionObjAddFinalizer (line 407) | func FunctionObjAddFinalizer(kubelessClient versioned.Interface, funcObj...
function FunctionObjHasFinalizer (line 414) | func FunctionObjHasFinalizer(funcObj *kubelessApi.Function, finalizerStr...
function FunctionObjRemoveFinalizer (line 425) | func FunctionObjRemoveFinalizer(kubelessClient versioned.Interface, func...
function GetAnnotationsFromCRD (line 443) | func GetAnnotationsFromCRD(clientset clientsetAPIExtensions.Interface, n...
function GetRandString (line 452) | func GetRandString(n int) (string, error) {
function GetSecretsAsLocalObjectReference (line 461) | func GetSecretsAsLocalObjectReference(secrets ...string) []v1.LocalObjec...
FILE: pkg/utils/k8sutil_test.go
function objBody (line 24) | func objBody(object interface{}) io.ReadCloser {
function fakeConfig (line 32) | func fakeConfig() *rest.Config {
function TestGetLocalHostname (line 45) | func TestGetLocalHostname(t *testing.T) {
function TestCreateAutoscaleResource (line 58) | func TestCreateAutoscaleResource(t *testing.T) {
function TestUpdateAutoscaleResource (line 81) | func TestUpdateAutoscaleResource(t *testing.T) {
function TestDeleteAutoscaleResource (line 120) | func TestDeleteAutoscaleResource(t *testing.T) {
function TestInitializeEmptyMapsInDeployment (line 143) | func TestInitializeEmptyMapsInDeployment(t *testing.T) {
function TestMergeDeployments (line 167) | func TestMergeDeployments(t *testing.T) {
function TestGetAnnotationsFromCRD (line 314) | func TestGetAnnotationsFromCRD(t *testing.T) {
FILE: pkg/utils/kubelessutil.go
constant secretsMountPath (line 55) | secretsMountPath = "/var/run/secrets/kubeless.io"
function GetFunctionPort (line 58) | func GetFunctionPort(clientset kubernetes.Interface, namespace, function...
function IsJSON (line 67) | func IsJSON(s string) bool {
function appendToCommand (line 73) | func appendToCommand(orig string, command ...string) string {
function getProvisionContainer (line 80) | func getProvisionContainer(function, checksum, fileName, handler, conten...
function addDefaultLabel (line 162) | func addDefaultLabel(labels map[string]string) map[string]string {
function hasDefaultLabel (line 170) | func hasDefaultLabel(labels map[string]string) bool {
function splitHandler (line 177) | func splitHandler(handler string) (string, string, error) {
function getFileName (line 187) | func getFileName(handler, funcContentType, runtime string, lr *langrunti...
function EnsureFuncConfigMap (line 204) | func EnsureFuncConfigMap(client kubernetes.Interface, funcObj *kubelessA...
function serviceSpec (line 258) | func serviceSpec(funcObj *kubelessApi.Function) v1.ServiceSpec {
function EnsureFuncService (line 278) | func EnsureFuncService(client kubernetes.Interface, funcObj *kubelessApi...
function getRuntimeVolumeMount (line 312) | func getRuntimeVolumeMount(name string) v1.VolumeMount {
function getChecksum (line 319) | func getChecksum(content string) (string, error) {
function populatePodSpec (line 333) | func populatePodSpec(funcObj *kubelessApi.Function, lr *langruntime.Lang...
function EnsureFuncImage (line 486) | func EnsureFuncImage(client kubernetes.Interface, funcObj *kubelessApi.F...
function svcTargetPort (line 596) | func svcTargetPort(funcObj *kubelessApi.Function) int32 {
function mergeMap (line 603) | func mergeMap(dst, src map[string]string) map[string]string {
function EnsureFuncDeployment (line 614) | func EnsureFuncDeployment(client kubernetes.Interface, funcObj *kubeless...
function CreateServiceMonitor (line 799) | func CreateServiceMonitor(smclient monitoringv1alpha1.MonitoringV1alpha1...
function GetOwnerReference (line 837) | func GetOwnerReference(kind, apiVersion, name string, uid types.UID) ([]...
function GetInClusterConfig (line 855) | func GetInClusterConfig() (*rest.Config, error) {
function getConfigLocation (line 871) | func getConfigLocation(apiExtensionsClientset clientsetAPIExtensions.Int...
function GetKubelessConfig (line 900) | func GetKubelessConfig(cli kubernetes.Interface, cliAPIExtensions client...
function DryRunFmt (line 915) | func DryRunFmt(format string, trigger interface{}) (string, error) {
function getCompressionType (line 935) | func getCompressionType(filename string) (compressionType string) {
function GetContentType (line 951) | func GetContentType(filename string) (string, error) {
function ParseContent (line 973) | func ParseContent(file, contentType string) (string, string, error) {
function getFileSha256 (line 1019) | func getFileSha256(file string) (string, error) {
function getSha256 (line 1035) | func getSha256(bytes []byte) (string, error) {
FILE: pkg/utils/kubelessutil_test.go
function getEnvValueFromList (line 20) | func getEnvValueFromList(envName string, l []v1.EnvVar) string {
function TestEnsureConfigMap (line 31) | func TestEnsureConfigMap(t *testing.T) {
function TestEnsureFuncMapWithoutDeps (line 88) | func TestEnsureFuncMapWithoutDeps(t *testing.T) {
function TestAvoidConfigMapOverwrite (line 160) | func TestAvoidConfigMapOverwrite(t *testing.T) {
function TestEnsureFileNames (line 176) | func TestEnsureFileNames(t *testing.T) {
function TestEnsureService (line 245) | func TestEnsureService(t *testing.T) {
function TestUpdateFuncSvc (line 311) | func TestUpdateFuncSvc(t *testing.T) {
function TestAvoidServiceOverwrite (line 368) | func TestAvoidServiceOverwrite(t *testing.T) {
function TestEnsureImage (line 391) | func TestEnsureImage(t *testing.T) {
function getDefaultFunc (line 473) | func getDefaultFunc(name, ns string) *kubelessApi.Function {
function prepareDeploymentTest (line 520) | func prepareDeploymentTest(funcName string) (*fake.Clientset, []metav1.O...
function TestEnsureDeployment (line 535) | func TestEnsureDeployment(t *testing.T) {
function TestEnsureDeploymentWithoutFuncNorHandler (line 727) | func TestEnsureDeploymentWithoutFuncNorHandler(t *testing.T) {
function TestEnsureDeploymentWithImage (line 744) | func TestEnsureDeploymentWithImage(t *testing.T) {
function TestEnsureDeploymentWithoutFunc (line 763) | func TestEnsureDeploymentWithoutFunc(t *testing.T) {
function TestEnsureUpdateDeployment (line 783) | func TestEnsureUpdateDeployment(t *testing.T) {
function TestAvoidDeploymentOverwrite (line 813) | func TestAvoidDeploymentOverwrite(t *testing.T) {
function TestDeploymentWithUnsupportedRuntime (line 829) | func TestDeploymentWithUnsupportedRuntime(t *testing.T) {
function TestDeploymentWithTimeout (line 843) | func TestDeploymentWithTimeout(t *testing.T) {
function TestDeploymentWithPrebuiltImage (line 862) | func TestDeploymentWithPrebuiltImage(t *testing.T) {
function TestDeploymentWithVolumes (line 883) | func TestDeploymentWithVolumes(t *testing.T) {
function TestEnsureDeploymentWithAffinityOverridden (line 916) | func TestEnsureDeploymentWithAffinityOverridden(t *testing.T) {
function doesNotContain (line 940) | func doesNotContain(envs []v1.EnvVar, env v1.EnvVar) bool {
function TestGetProvisionContainer (line 949) | func TestGetProvisionContainer(t *testing.T) {
FILE: pkg/utils/metrics.go
type Metric (line 28) | type Metric struct
type MetricsRetriever (line 40) | type MetricsRetriever interface
type PrometheusMetricsHandler (line 45) | type PrometheusMetricsHandler struct
method GetRawMetrics (line 104) | func (h *PrometheusMetricsHandler) GetRawMetrics(apiV1Client kubernete...
function parseMetrics (line 47) | func parseMetrics(namespace, functionName string, rawMetrics []byte) ([]...
function GetFunctionMetrics (line 116) | func GetFunctionMetrics(apiV1Client kubernetes.Interface, h MetricsRetri...
Condensed preview — 273 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,000K chars).
[
{
"path": ".circleci/config.yml",
"chars": 7395,
"preview": "version: 2\n\n## Definitions\nbuild_allways: &build_allways\n filters:\n tags:\n only: /.*/\ndefaults: &defaults\n env"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 165,
"preview": "**Issue Ref**: [Issue number related to this PR or None]\n \n**Description**: \n\n[PR Description]\n\n**TODOs**:\n - [ ] Ready "
},
{
"path": ".github/issue_template.md",
"chars": 351,
"preview": "**Is this a BUG REPORT or FEATURE REQUEST?**:\n\n**What happened**:\n\n**What you expected to happen**:\n\n**How to reproduce "
},
{
"path": ".gitignore",
"chars": 2548,
"preview": "### Go ###\n# Binaries for programs and plugins\n*.exe\n*.dll\n*.so\n*.dylib\n\n# Test binary, build with `go test -c`\n*.test\n\n"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3219,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": "CONTRIBUTING.md",
"chars": 2699,
"preview": "# Contributing Guidelines\n\n## License and CLA\n\nThe Kubeless license is Apache Software License V2\n\nWe do not currently a"
},
{
"path": "LICENSE",
"chars": 11346,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "Makefile",
"chars": 2836,
"preview": "GO = go\nGO_FLAGS =\nGOFMT = gofmt\nKUBECFG = kubecfg\nDOCKER = docker\nCONTROLLER_IMAGE = kubeless-function-controller:lates"
},
{
"path": "OWNERS",
"chars": 138,
"preview": "Kubeless - A Bitnami Project\n\nEngineering manager:\n - ppbaena\n\nEmeritus maintainers:\n - ngtuna\n - andresmgot\n - angu"
},
{
"path": "README.md",
"chars": 3322,
"preview": "# <img src=\"https://cloud.githubusercontent.com/assets/4056725/25480209/1d5bf83c-2b48-11e7-8db8-bcd650f31297.png\" alt=\"K"
},
{
"path": "cmd/function-controller/function-controller.go",
"chars": 2257,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/autoscale/autoscale.go",
"chars": 3068,
"preview": "/*\nCopyright 2016 Skippbox, Ltd.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this fi"
},
{
"path": "cmd/kubeless/autoscale/autoscaleCreate.go",
"chars": 2535,
"preview": "package autoscale\n\nimport (\n\t\"github.com/kubeless/kubeless/pkg/utils\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/spf13/c"
},
{
"path": "cmd/kubeless/autoscale/autoscaleDelete.go",
"chars": 1930,
"preview": "/*\nCopyright 2016 Skippbox, Ltd.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this fi"
},
{
"path": "cmd/kubeless/autoscale/autoscaleList.go",
"chars": 3415,
"preview": "/*\nCopyright 2016 Skippbox, Ltd.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this fi"
},
{
"path": "cmd/kubeless/autoscale/autoscaleList_test.go",
"chars": 2821,
"preview": "package autoscale\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\t\"testing\"\n\n\tav2alpha1 \"k8s.io/api/autoscaling/v2beta1\"\n\t\"k8s.io/api/cor"
},
{
"path": "cmd/kubeless/autoscale/autoscale_test.go",
"chars": 1596,
"preview": "package autoscale\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"k8s.io/api/autoscaling/v2beta1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/ap"
},
{
"path": "cmd/kubeless/completion/completion.go",
"chars": 2106,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/function/call.go",
"chars": 3504,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/function/delete.go",
"chars": 1481,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/function/deploy.go",
"chars": 10312,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/function/describe.go",
"chars": 3165,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/function/function.go",
"chars": 8377,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/function/function_test.go",
"chars": 17622,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/function/list.go",
"chars": 6028,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/function/list_test.go",
"chars": 6171,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/function/logs.go",
"chars": 2173,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/function/top.go",
"chars": 4118,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/function/top_test.go",
"chars": 17839,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/function/update.go",
"chars": 7670,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/getserverconfig/getServerConfig.go",
"chars": 928,
"preview": "package getserverconfig\n\nimport (\n\t\"strings\"\n\n\t\"github.com/kubeless/kubeless/pkg/langruntime\"\n\t\"github.com/kubeless/kube"
},
{
"path": "cmd/kubeless/kubeless.go",
"chars": 1533,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/topic/topic.go",
"chars": 1220,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/topic/topicCreate.go",
"chars": 2780,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/topic/topicDelete.go",
"chars": 1800,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/topic/topicList.go",
"chars": 1673,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/topic/topicPublish.go",
"chars": 2885,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/cronjob/create.go",
"chars": 4749,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/cronjob/cronjob_trigger.go",
"chars": 2175,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/cronjob/delete.go",
"chars": 1803,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/cronjob/list.go",
"chars": 2240,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/cronjob/update.go",
"chars": 4436,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/http/create.go",
"chars": 5893,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/http/delete.go",
"chars": 1779,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/http/http_trigger.go",
"chars": 1120,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/http/list.go",
"chars": 2173,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/http/update.go",
"chars": 4901,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/kafka/create.go",
"chars": 3615,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/kafka/delete.go",
"chars": 1795,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/kafka/kafka_trigger.go",
"chars": 1132,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/kafka/list.go",
"chars": 2251,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/kafka/update.go",
"chars": 3380,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/kinesis/create.go",
"chars": 5137,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/kinesis/delete.go",
"chars": 1826,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/kinesis/kinesis_trigger.go",
"chars": 1246,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/kinesis/list.go",
"chars": 2302,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/kinesis/publish.go",
"chars": 4702,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/kinesis/stream_create.go",
"chars": 4166,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/kinesis/update.go",
"chars": 4143,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/nats/create.go",
"chars": 3580,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/nats/delete.go",
"chars": 1781,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/nats/list.go",
"chars": 2245,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/nats/nats_trigger.go",
"chars": 1159,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/nats/publish.go",
"chars": 1967,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/nats/update.go",
"chars": 3353,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/trigger/trigger.go",
"chars": 1491,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "cmd/kubeless/version/version.go",
"chars": 939,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "docker/dev-environment/Dockerfile",
"chars": 1118,
"preview": "FROM docker:17.11.0-ce-dind\n\nENV GOPATH=/go\nENV PATH=$GOPATH/bin:/usr/local/go/bin:/usr/local/bats/bin:$PATH \\\n CGO_E"
},
{
"path": "docker/dev-environment/entry-point.sh",
"chars": 551,
"preview": "#!/bin/bash\n\nif [ ! -d \"$GOPATH/src/github.com/kubeless/kubeless\" ]; then\n echo \"Kubeless directory not found\"\n ex"
},
{
"path": "docker/event-sources/kubernetes/Dockerfile",
"chars": 452,
"preview": "FROM bitnami/minideb:jessie\n\nRUN install_packages python3 curl ca-certificates git\nRUN curl https://bootstrap.pypa.io/ge"
},
{
"path": "docker/event-sources/kubernetes/README.md",
"chars": 508,
"preview": "# Container to feed k8s events to kafka\n\n`events.py` is a Python 3.4 script, that uses `asyncio` and the Kubernetes pyth"
},
{
"path": "docker/event-sources/kubernetes/events.py",
"chars": 3189,
"preview": "import asyncio\nimport logging\nimport json\n\nfrom kubernetes import client, config, watch\n\nfrom kafka import KafkaProducer"
},
{
"path": "docker/function-controller/Dockerfile",
"chars": 176,
"preview": "FROM bitnami/minideb:jessie\n\nRUN install_packages ca-certificates\n\nADD kubeless-function-controller /kubeless-function-c"
},
{
"path": "docker/function-image-builder/Dockerfile",
"chars": 119,
"preview": "FROM fedora:27\n\nRUN dnf install -y skopeo nodejs\n\nADD imbuilder /\nADD entrypoint.sh /\n\nENTRYPOINT [ \"/entrypoint.sh\" ]\n"
},
{
"path": "docker/function-image-builder/entrypoint.sh",
"chars": 961,
"preview": "#!/bin/bash\n\n# Copyright (c) 2016-2017 Bitnami\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you"
},
{
"path": "docker/runtime/README.md",
"chars": 259,
"preview": "Kubeless Runtimes has been migrated to it's own repository. You can find them here: https://github.com/kubeless/runtimes"
},
{
"path": "docker/unzip/Dockerfile",
"chars": 93,
"preview": "FROM bitnami/minideb\nRUN install_packages unzip curl ca-certificates tar gzip bzip2 xz-utils\n"
},
{
"path": "docs/GKE-deployment.md",
"chars": 4651,
"preview": "# Deploying Kubeless to Google Kubernetes Engine (GKE)\n\nThis guide goes over the required steps for deploying Kubeless i"
},
{
"path": "docs/README.md",
"chars": 259,
"preview": "# Kubeless Docs\n\nThis folder holds the documentation that is served in [https://kubeless.io/docs](https://kubeless.io/do"
},
{
"path": "docs/advanced-function-deployment.md",
"chars": 7248,
"preview": "# Deploying Kubeless Functions using Kubernetes API\n\nApart from using the `kubeless` CLI, it is possible to deploy Kubel"
},
{
"path": "docs/architecture.md",
"chars": 12724,
"preview": "# Kubeless architecture\n\nThis doc covers the architectural design of Kubeless and directory structure of the repository."
},
{
"path": "docs/autoscaling.md",
"chars": 3209,
"preview": "# Autoscaling function deployment in Kubeless\n\nThis document gives you an overview of how we do autoscaling for function"
},
{
"path": "docs/building-functions.md",
"chars": 5548,
"preview": "# Build process for functions\n\n> **Warning**: This feature is still under heavy development\n\nKubeless includes a way of "
},
{
"path": "docs/cronjob-triggers.md",
"chars": 3784,
"preview": "# Scheduling the trigger of a function \n\nKubeless has its own CronJobTrigger which uses [Kubernetes CronJob](https://kub"
},
{
"path": "docs/debug-functions.md",
"chars": 7608,
"preview": "# Debug Kubeless Functions\n\nIn this document we will show how you can debug your function in order to spot possible erro"
},
{
"path": "docs/debugging.md",
"chars": 4757,
"preview": "# Debugging Kubeless\n\nAs a developer you'll probably be interested on the investigation of Kubeless code. A possible res"
},
{
"path": "docs/dev-guide.md",
"chars": 8815,
"preview": "# Kubeless developer guide\n\nThis will cover the steps need to be done in order to build your local development environme"
},
{
"path": "docs/function-controller-configuration.md",
"chars": 11518,
"preview": "# Controller configurations for Functions\n\n## Using ConfigMap\n\nConfigurations for functions can be done in `ConfigMap`: "
},
{
"path": "docs/http-triggers.md",
"chars": 14774,
"preview": "# Expose and secure Kubeless functions\n\nKubeless leverages [Kubernetes ingress](https://kubernetes.io/docs/concepts/serv"
},
{
"path": "docs/implementing-new-runtime.md",
"chars": 406,
"preview": "# How to implement a new Kubeless run time\n\nRuntimes are developed in this repository:\n\n[https://github.com/kubeless/run"
},
{
"path": "docs/implementing-new-trigger.md",
"chars": 6344,
"preview": "# How to add a new event source as Trigger\n\nKubeless [architecture](/docs/architecture) is built on core concepts of Fun"
},
{
"path": "docs/kubeless-functions.md",
"chars": 4631,
"preview": "# Kubeless Functions\n\nFunctions are the main entity in Kubeless. It is possible to write Functions in different language"
},
{
"path": "docs/kubeless-on-AKS.md",
"chars": 1610,
"preview": "# Kubeless on Azure Kubernetes Service\n\n## 1. Introduction\n\nThis guide goes over the required steps for deploying Kubele"
},
{
"path": "docs/misc/kafka-pv-gke.yaml",
"chars": 271,
"preview": "apiVersion: v1\nkind: PersistentVolume\nmetadata:\n name: kafka-pv\n labels:\n kubeless: kafka\nspec:\n capacity:\n sto"
},
{
"path": "docs/misc/kubeless-grafana-dashboard.json",
"chars": 7474,
"preview": "{\n \"id\": 1,\n \"title\": \"Kubeless\",\n \"description\": \"Dashboard for Kubeless\",\n \"tags\": [],\n \"style\": \"dark\",\n \"timez"
},
{
"path": "docs/misc/zookeeper-pv-gke.yaml",
"chars": 283,
"preview": "apiVersion: v1\nkind: PersistentVolume\nmetadata:\n name: zookeeper-pv\n labels:\n kubeless: zookeeper\nspec:\n capacity:"
},
{
"path": "docs/monitoring.md",
"chars": 604,
"preview": "# Monitoring\n\n## Prometheus\n\nKubeless monitoring relies on Prometheus. The language runtimes are instrumented to automat"
},
{
"path": "docs/proposals/decoupling-triggers-and-runtimes.md",
"chars": 7649,
"preview": "# Decoupling triggers and runtimes\n\n## Definition of the problem\nCurrently for each new runtime we need to add a contain"
},
{
"path": "docs/proposals/http-triggers.md",
"chars": 5534,
"preview": "# http trigger improvements\n\nThough there is no standard on what http/https triggers of FAAS platform should support, mo"
},
{
"path": "docs/pubsub-functions.md",
"chars": 5785,
"preview": "# PubSub events\n\nYou can trigger any Kubeless function by a PubSub mechanism. The PubSub function is expected to consume"
},
{
"path": "docs/quick-start.md",
"chars": 6501,
"preview": "# Installation\n\nInstallation is made of three steps:\n\n* Download the `kubeless` CLI from the [release page](https://gith"
},
{
"path": "docs/release-flow.md",
"chars": 3855,
"preview": "# Introduction\n\nKubeless leverages [travis-ci](https://travis-ci.org/) to construct an automated release flow. A release"
},
{
"path": "docs/runtimes.md",
"chars": 23113,
"preview": "# Kubeless Runtime Variants\n\nBy default Kubeless has support for runtimes in different states: stable and incubator. You"
},
{
"path": "docs/streaming-functions.md",
"chars": 6850,
"preview": "# Data Stream events\n\nKubeless lets you trigger any Kubeless function in response to ingested records into a data stream"
},
{
"path": "docs/triggers.md",
"chars": 1033,
"preview": "# Triggers\n\nTo invoke deployed functions, you need to create **triggers**. A function can have multiple triggers, but ea"
},
{
"path": "docs/troubleshooting.md",
"chars": 1977,
"preview": "# Troubleshooting\n\n## Installation\n\nIf installing using\n\n```console\nkubectl create -f kubeless.yaml --namespace kubeless"
},
{
"path": "docs/use-existing-kafka.md",
"chars": 6778,
"preview": "# Use an existing Kafka cluster with Kubeless\n\nIn Kubeless [release page](https://github.com/kubeless/kubeless/releases)"
},
{
"path": "examples/Makefile",
"chars": 37407,
"preview": "GIT_SHA1 ?= master\nBASE_URL := https://raw.githubusercontent.com/kubeless/kubeless/$(GIT_SHA1)\n\nget-python:\n\tkubeless fu"
},
{
"path": "examples/README.md",
"chars": 560,
"preview": "# Examples\n\nThis directory contains basic examples for kubeless.\n\nSpecifically it contains examples that we can test qui"
},
{
"path": "examples/ballerina/hello_with_conf/hello_with_conf.bal",
"chars": 263,
"preview": "import kubeless/kubeless;\nimport ballerina/io;\nimport ballerina/config;\n\npublic function bar(kubeless:Event event, kubel"
},
{
"path": "examples/ballerina/hello_with_conf/kubeless.toml",
"chars": 36,
"preview": "[hello]\nuserid=\"john@ballerina.com\"\n"
},
{
"path": "examples/ballerina/helloget.bal",
"chars": 158,
"preview": "import kubeless/kubeless;\n\npublic function foo(kubeless:Event event, kubeless:Context context) returns (string|error) {\n"
},
{
"path": "examples/ballerina/hellowithdata.bal",
"chars": 222,
"preview": "import kubeless/kubeless;\nimport ballerina/io;\n\npublic function foo(kubeless:Event event, kubeless:Context context) retu"
},
{
"path": "examples/dotnetcore/dependency-yaml.cs",
"chars": 511,
"preview": "using System;\r\nusing Kubeless.Functions;\r\nusing YamlDotNet.Serialization;\r\n\r\npublic class module\r\n{\r\n public string h"
},
{
"path": "examples/dotnetcore/dependency-yaml.csproj",
"chars": 300,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <PropertyGroup>\n <TargetFramework>netstandard2.0</TargetFramework>\n </PropertyG"
},
{
"path": "examples/dotnetcore/fibonacci.cs",
"chars": 390,
"preview": "using System;\r\nusing Kubeless.Functions;\r\n\r\npublic class module\r\n{\r\n public int handler(Event k8Event, Context k8Cont"
},
{
"path": "examples/dotnetcore/fibonacci.csproj",
"chars": 238,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <PropertyGroup>\n <TargetFramework>netstandard2.0</TargetFramework>\n </PropertyG"
},
{
"path": "examples/dotnetcore/helloget.cs",
"chars": 167,
"preview": "using System;\nusing Kubeless.Functions;\n\npublic class module\n{\n public string handler(Event k8Event, Context k8Contex"
},
{
"path": "examples/dotnetcore/helloget.csproj",
"chars": 238,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <PropertyGroup>\n <TargetFramework>netstandard2.0</TargetFramework>\n </PropertyG"
},
{
"path": "examples/dotnetcore/hellowithdata.cs",
"chars": 166,
"preview": "using System;\nusing Kubeless.Functions;\n\npublic class module\n{\n public object handler(Event k8Event, Context k8Contex"
},
{
"path": "examples/dotnetcore/hellowithdata.csproj",
"chars": 238,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <PropertyGroup>\n <TargetFramework>netstandard2.0</TargetFramework>\n </PropertyG"
},
{
"path": "examples/golang/go.mod",
"chars": 73,
"preview": "module function\n\ngo 1.14\n\nrequire (\n\tgithub.com/sirupsen/logrus v1.6.0\n)\n"
},
{
"path": "examples/golang/helloget.go",
"chars": 206,
"preview": "package kubeless\n\nimport (\n\t\"github.com/kubeless/kubeless/pkg/functions\"\n)\n\n// Foo sample function\nfunc Foo(event functi"
},
{
"path": "examples/golang/hellowithdata.go",
"chars": 248,
"preview": "package kubeless\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/kubeless/kubeless/pkg/functions\"\n)\n\n// Handler sample function with data"
},
{
"path": "examples/golang/hellowithdeps.go",
"chars": 283,
"preview": "package kubeless\n\nimport (\n\t\"github.com/kubeless/kubeless/pkg/functions\"\n\t\"github.com/sirupsen/logrus\"\n)\n\n// Hello sampl"
},
{
"path": "examples/java/HelloGet.java",
"chars": 213,
"preview": "package io.kubeless;\n\nimport io.kubeless.Event;\nimport io.kubeless.Context;\n\npublic class Foo {\n public String foo(io"
},
{
"path": "examples/java/HelloWithData.java",
"chars": 249,
"preview": "package io.kubeless;\n\nimport io.kubeless.Event;\nimport io.kubeless.Context;\n\npublic class Foo {\n public String foo(io"
},
{
"path": "examples/java/HelloWithDeps.java",
"chars": 380,
"preview": "package io.kubeless;\n\nimport io.kubeless.Event;\nimport io.kubeless.Context;\n\nimport org.joda.time.LocalTime;\n\npublic cla"
},
{
"path": "examples/java/pom.xml",
"chars": 825,
"preview": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocat"
},
{
"path": "examples/jvm/Readme.md",
"chars": 138,
"preview": "# JVM exampels\nThese are examples to run compiled jvm code in kubeless.\nThey should serve as a template to be able to us"
},
{
"path": "examples/jvm/java/Readme.md",
"chars": 252,
"preview": "# Java on runtime JVM\n\n`gradle shadowJar` Build the jar with all deps\n\n`kubeless function deploy test --runtime jvm1.8 -"
},
{
"path": "examples/jvm/java/build.gradle",
"chars": 631,
"preview": "buildscript {\n repositories {\n jcenter()\n }\n dependencies {\n classpath 'com.github.jengelman.grad"
},
{
"path": "examples/jvm/java/src/main/java/io/ino/Handler.java",
"chars": 230,
"preview": "package io.ino;\n\npublic class Handler {\n public String sayHello(io.kubeless.Event event, io.kubeless.Context cont"
},
{
"path": "examples/jvm/scala/Readme.md",
"chars": 353,
"preview": "# Scala on runtime JVM\n\n!! WIP the jar-file is to large for the storage backend, you have to pass a url to the jar file."
},
{
"path": "examples/jvm/scala/build.sbt",
"chars": 167,
"preview": "\nassemblyJarName in assembly := \"scala-test.jar\"\norganization := \"de.inoio\"\nscalaVersion := \"2.12.1\"\nlibraryDependencies"
},
{
"path": "examples/jvm/scala/project/assembly.sbt",
"chars": 57,
"preview": "addSbtPlugin(\"com.eed3si9n\" % \"sbt-assembly\" % \"0.14.7\")\n"
},
{
"path": "examples/jvm/scala/project/build.properties",
"chars": 20,
"preview": "sbt.version=0.13.15\n"
},
{
"path": "examples/jvm/scala/src/main/scala/de/inoio/Handler.scala",
"chars": 160,
"preview": "package de.inoio\n\nimport io.kubeless.{Context, Event}\n\nclass Handler {\n def fooBar(event: Event, context: Context): Str"
},
{
"path": "examples/nodejs/function.yaml",
"chars": 255,
"preview": "---\napiVersion: kubeless.io/v1beta1\nkind: Function\nmetadata:\n name: hello\nspec:\n handler: handler.hello\n runtime: nod"
},
{
"path": "examples/nodejs/function1.yaml",
"chars": 256,
"preview": "---\napiVersion: kubeless.io/v1beta1\nkind: Function\nmetadata:\n name: hello\nspec:\n handler: handler.foobar\n runtime: no"
},
{
"path": "examples/nodejs/helloget.js",
"chars": 87,
"preview": "module.exports = {\n foo: function (event, context) {\n return 'hello world!';\n }\n}\n"
},
{
"path": "examples/nodejs/hellostream.js",
"chars": 735,
"preview": "const from = require('from2');\nconst eos = require('end-of-stream');\n\nfunction fromString(string) {\n return from(func"
},
{
"path": "examples/nodejs/hellowithdata.js",
"chars": 107,
"preview": "module.exports = {\n handler: (event, context) => {\n console.log(event);\n return event.data;\n },\n};\n"
},
{
"path": "examples/nodejs/hellowithdeps.js",
"chars": 216,
"preview": "'use strict';\n\nconst _ = require('lodash');\n\nmodule.exports = {\n handler: (event, context) => {\n _.assign(even"
},
{
"path": "examples/nodejs/index.js",
"chars": 132,
"preview": "'use strict';\n\nmodule.exports = {\n helloGet: require('./helloget').foo,\n helloWithData: require('./hellowithdata')"
},
{
"path": "examples/nodejs/package.json",
"chars": 175,
"preview": "{\n \"name\": \"hellowithdeps\",\n \"version\": \"0.0.1\",\n \"dependencies\": {\n \"end-of-stream\": \"^1.4.1\",\n "
},
{
"path": "examples/php/composer.json",
"chars": 56,
"preview": "{\n \"require\": {\n \"monolog/monolog\": \"^1.23\"\n }\n}\n"
},
{
"path": "examples/php/helloget.php",
"chars": 67,
"preview": "<?php\n\nfunction foo($event, $context) {\n return \"hello world\";\n}\n\n"
},
{
"path": "examples/php/hellowithdata.php",
"chars": 79,
"preview": "<?php\n\nfunction foo($event, $context) {\n return json_encode($event->data);\n}\n\n"
},
{
"path": "examples/php/hellowithdeps.php",
"chars": 354,
"preview": "<?php\n\nrequire 'vendor/autoload.php';\n\nuse Monolog\\Logger;\nuse Monolog\\Handler\\StreamHandler;\n\nfunction foo($event, $con"
},
{
"path": "examples/python/Dockerfile",
"chars": 340,
"preview": "# Create a custom image with a python function\nFROM kubeless/python@sha256:565bebecb08d9a7b804c588105677a3572f10ff2032ce"
},
{
"path": "examples/python/function.yaml",
"chars": 208,
"preview": "---\napiVersion: k8s.io/v1\nkind: Function\nmetadata:\n name: function\nspec:\n handler: hello.handler\n runtime: python3.7\n"
},
{
"path": "examples/python/function1.yaml",
"chars": 577,
"preview": "---\napiVersion: kubeless.io/v1beta1\nkind: Function\nmetadata:\n name: function1\nspec:\n handler: hello.foobar\n runtime: "
},
{
"path": "examples/python/helloget.py",
"chars": 50,
"preview": "def foo(event, context):\n return \"hello world\"\n"
},
{
"path": "examples/python/hellowithdata.py",
"chars": 71,
"preview": "def handler(event, context):\n print(event)\n return event['data']\n"
},
{
"path": "examples/python/hellowithdeps.py",
"chars": 35,
"preview": "from hellowithdepshelper import foo"
},
{
"path": "examples/python/hellowithdepshelper.py",
"chars": 221,
"preview": "from bs4 import BeautifulSoup\nimport urllib.request\n\ndef foo(event, context):\n page = urllib.request.urlopen(\"https:/"
},
{
"path": "examples/python/requirements.txt",
"chars": 3,
"preview": "bs4"
},
{
"path": "examples/ruby/Gemfile",
"chars": 45,
"preview": "source 'https://rubygems.org'\n\ngem 'logging'\n"
},
{
"path": "examples/ruby/function.yaml",
"chars": 831,
"preview": "---\napiVersion: kubeless.io/v1beta1\nkind: Function\nmetadata:\n name: function\nspec:\n handler: test.run\n runtime: ruby2"
},
{
"path": "examples/ruby/helloget.rb",
"chars": 44,
"preview": "def foo(event, context)\n \"hello world\"\nend\n"
},
{
"path": "examples/ruby/hellowithdata.rb",
"chars": 75,
"preview": "def handler(event, context)\n puts event\n JSON.generate(event[:data])\nend\n"
},
{
"path": "examples/ruby/hellowithdeps.rb",
"chars": 125,
"preview": "require 'logging'\n\ndef foo(event, context)\n logging = Logging.logger(STDOUT)\n logging.info \"it works!\"\n \"hello world\""
},
{
"path": "examples/ruby/latest.rb",
"chars": 592,
"preview": "# Obtains the latest Kubeless release published \ndef handler(event, context)\n require \"net/https\"\n require \"uri\"\n req"
},
{
"path": "go.mod",
"chars": 1976,
"preview": "module github.com/kubeless/kubeless\n\ngo 1.12\n\nrequire (\n\tgithub.com/Azure/go-autorest v8.0.0+incompatible // indirect\n\tg"
},
{
"path": "go.sum",
"chars": 55011,
"preview": "cloud.google.com/go v0.0.0-20160913182117-3b1ae45394a2/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.goog"
},
{
"path": "hack/boilerplate.go.txt",
"chars": 563,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "hack/update-codegen.sh",
"chars": 1546,
"preview": "#!/bin/bash\n\n# Copyright 2017 The Kubernetes Authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "kubeless-non-rbac.jsonnet",
"chars": 3997,
"preview": "local k = import \"ksonnet.beta.1/k.libsonnet\";\nlocal runtimesSrc = import \"runtimes.jsonnet\";\n\nlocal objectMeta = k.core"
},
{
"path": "kubeless-openshift.jsonnet",
"chars": 721,
"preview": "# Builds on kubeless.ksonnet to produce a deployable manifest on OpenShift 1.5\n# Modifies apiVersion for kubeless-contro"
},
{
"path": "kubeless.jsonnet",
"chars": 2701,
"preview": "# Add RBAC role and binding on top of kubeless.jsonnet, to allow\n# kubeless controller to deploy/update/etc functions on"
},
{
"path": "manifests/README.md",
"chars": 257,
"preview": "# Collection of manifests for development\n\n**NOTE: TO INSTALL KUBELESS USE A RELEASED MANIFEST AT https://github.com/kub"
},
{
"path": "manifests/autoscaling/custom-metrics.yaml",
"chars": 3124,
"preview": "kind: Namespace\napiVersion: v1\nmetadata:\n name: custom-metrics\n---\nkind: ServiceAccount\napiVersion: v1\nmetadata:\n name"
},
{
"path": "manifests/autoscaling/prometheus-operator.yaml",
"chars": 1583,
"preview": "apiVersion: rbac.authorization.k8s.io/v1beta1\nkind: ClusterRole\nmetadata:\n name: prometheus-operator\nrules:\n- apiGroups"
},
{
"path": "manifests/autoscaling/sample-metrics-app.yaml",
"chars": 1498,
"preview": "apiVersion: apps/v1beta1\nkind: Deployment\nmetadata:\n labels:\n app: sample-metrics-app\n name: sample-metrics-app\nspe"
},
{
"path": "manifests/autoscaling/sample-prometheus-instance.yaml",
"chars": 1308,
"preview": "apiVersion: rbac.authorization.k8s.io/v1beta1\nkind: ClusterRole\nmetadata:\n name: prometheus\nrules:\n- apiGroups:\n - \"\"\n"
},
{
"path": "manifests/kinesis/kinesalite.yaml",
"chars": 510,
"preview": "---\napiVersion: v1\nkind: Service\nmetadata:\n annotations:\n name: kinesis\n labels:\n app: kinesis\nspec:\n type: NodeP"
},
{
"path": "manifests/monitoring/grafana-configmap.yaml",
"chars": 53648,
"preview": "apiVersion: v1\ndata:\n grafana-net-2-dashboard.json: |\n {\n \"__inputs\": [{\n \"name\": \"DS_PROMETHEUS\",\n "
},
{
"path": "manifests/monitoring/grafana-deployment.yaml",
"chars": 1253,
"preview": "apiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n name: grafana-core\n namespace: monitoring\n labels:\n app"
},
{
"path": "manifests/monitoring/grafana-job.yaml",
"chars": 2095,
"preview": "apiVersion: batch/v1\nkind: Job\nmetadata:\n name: grafana-import-dashboards\n namespace: monitoring\n labels:\n app: gr"
},
{
"path": "manifests/monitoring/grafana-service.yaml",
"chars": 224,
"preview": "apiVersion: v1\nkind: Service\nmetadata:\n name: grafana\n namespace: monitoring\n labels:\n app: grafana\n component:"
},
{
"path": "manifests/monitoring/prometheus.yaml",
"chars": 4962,
"preview": "apiVersion: v1\nkind: Namespace\nmetadata:\n name: monitoring\n---\nkind: ConfigMap\nmetadata:\n name: prometheus-config\n na"
},
{
"path": "manifests/nats/nats-cluster.yaml",
"chars": 111,
"preview": "apiVersion: \"nats.io/v1alpha2\"\nkind: \"NatsCluster\"\nmetadata:\n name: \"nats\"\nspec:\n size: 2\n version: \"1.1.0\"\n"
},
{
"path": "manifests/ui/README.md",
"chars": 170,
"preview": "# Kubeless UI\n\nYou can find the latest manifest for deploying the UI in the releases page of the kubeless-ui repository:"
},
{
"path": "pkg/apis/kubeless/register.go",
"chars": 102,
"preview": "package kubeless\n\nconst (\n\t// GroupName is ApiGroup for the Kubeless API\n\tGroupName = \"kubeless.io\"\n)\n"
},
{
"path": "pkg/apis/kubeless/v1beta1/doc.go",
"chars": 698,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "pkg/apis/kubeless/v1beta1/function.go",
"chars": 2589,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "pkg/apis/kubeless/v1beta1/register.go",
"chars": 1263,
"preview": "package v1beta1\n\nimport (\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\t\"k8s.io/api"
},
{
"path": "pkg/apis/kubeless/v1beta1/zz_generated.deepcopy.go",
"chars": 3087,
"preview": "// +build !ignore_autogenerated\n\n/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the"
},
{
"path": "pkg/client/clientset/versioned/clientset.go",
"chars": 3107,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "pkg/client/clientset/versioned/doc.go",
"chars": 640,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "pkg/client/clientset/versioned/fake/clientset_generated.go",
"chars": 2643,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "pkg/client/clientset/versioned/fake/doc.go",
"chars": 640,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "pkg/client/clientset/versioned/fake/register.go",
"chars": 1750,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "pkg/client/clientset/versioned/scheme/doc.go",
"chars": 656,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "pkg/client/clientset/versioned/scheme/register.go",
"chars": 1752,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "pkg/client/clientset/versioned/typed/kubeless/v1beta1/doc.go",
"chars": 642,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "pkg/client/clientset/versioned/typed/kubeless/v1beta1/fake/doc.go",
"chars": 633,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "pkg/client/clientset/versioned/typed/kubeless/v1beta1/fake/fake_function.go",
"chars": 4456,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
},
{
"path": "pkg/client/clientset/versioned/typed/kubeless/v1beta1/fake/fake_kubeless_client.go",
"chars": 1140,
"preview": "/*\nCopyright (c) 2016-2017 Bitnami\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this"
}
]
// ... and 73 more files (download for full content)
About this extraction
This page contains the full source code of the skippbox/kubeless GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 273 files (24.9 MB), approximately 263.6k tokens, and a symbol index with 485 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.