eneco / landscaper Goto Github PK
View Code? Open in Web Editor NEWDeprecated. Takes a set of Helm Chart references with values (a desired state), and realizes this in a Kubernetes cluster
License: Apache License 2.0
Deprecated. Takes a set of Helm Chart references with values (a desired state), and realizes this in a Kubernetes cluster
License: Apache License 2.0
Since existing non-landscape secrets will cause the real deal to fail
Two lists are compared, order of the elements in the lists is random. Current (f073f7e) example-secretive
triggers this bug, e.g.:
[2017-01-04T09:40:10+01:00] INFO Diff:
--- Current example-secretive
+++ Desired example-secretive
@@ -15,7 +15,7 @@
"sleep": 1
},
"secrets": [
- "hello-age",
- "hello-name"
+ "hello-name",
+ "hello-age"
]
}
which shouldn't trigger an update.
Have set up the Helm and Tiller with v2.3.1. helm version does report the expected version:
$ helm version
Client: &version.Version{SemVer:"v2.3.1", GitCommit:"32562a3040bb5ca690339b9840b6f60f8ce25da4", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.3.1", GitCommit:"32562a3040bb5ca690339b9840b6f60f8ce25da4", GitTreeState:"clean"}
$ helm list
$
However, the landscaper apply shows the helmClientVersion=v2.4 and keeps failing:
$ landscaper apply test.yaml --namespace test -v
[2017-06-09T02:41:07Z] INFO This is Landscaper v1.0.6-rc.1 commit=3e47462b0fdff641b8b7dc6029f635de5a14126e tag=1.0.6-rc.1
[2017-06-09T02:41:07Z] INFO Apply landscape desired state dir= dryRun=false helmHome=/root/.helm namespace=test releasePrefix=test- verbose=true
[2017-06-09T02:41:07Z] DEBUG Setup Kubernetes Client
[2017-06-09T02:41:07Z] INFO Connected to Kubernetes kubernetesVersion=v1.6.4
[2017-06-09T02:41:07Z] DEBUG Setup Helm Client helmClientVersion=v2.4
[2017-06-09T02:41:07Z] DEBUG Create tiller tunnel tillerNamespace=kube-system
[2017-06-09T02:41:07Z] DEBUG Created tiller tunnel port=44217
[2017-06-09T02:41:07Z] INFO Connected to Tiller clientServerCompatible=false tillerVersion=v2.3.1
[2017-06-09T02:41:07Z] WARN Helm and Tiller report incompatible version numbers
[2017-06-09T02:41:07Z] INFO Obtain desired state from files files=[test.yaml]
[2017-06-09T02:41:07Z] DEBUG Read desired state from file file=test.yaml
...
[2017-06-09T02:41:07Z] DEBUG Desired state has been read n_components=1
[2017-06-09T02:41:07Z] INFO Obtain current state Helm Releases (Components) from Tiller
[2017-06-09T02:41:07Z] DEBUG listHelmReleases
[2017-06-09T02:41:07Z] ERROR Loading current state failed error=rpc error: code = Unknown desc = incompatible versions client: v2.4+unreleased server: v2.3.1
Error: rpc error: code = Unknown desc = incompatible versions client: v2.4+unreleased server: v2.3.1
Curling the latest 1.0.5 binaries for linux amd64 won't run inside the alpine:3.6 image.
It did run in a slim image.
I have a feeling this is because the executable is dynamically linked... Looking into it now.
ldd landscaper
/lib64/ld-linux-x86-64.so.2 (0x559eec9ae000)
libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x559eec9ae000)
libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x559eec9ae000)
We were able to resolve this by installing the following on alpine:
apk add libc6-compat
So basically, this comes down to alpine having muslibc.
Would it be possible to start compiling and statically linking against musl?
Are you open to a PR for that?
Expected: Error saying chart doesn't exist (maybe a helm repo update could be run).
Actual: Just uses the latest one from helm cache ignoring the version
Also, if there did exist that version, but I hadn't updated my helm repo it would just silently use the one that I had as the chartPath
instead of error/warning.
$ cat test/redis.yaml
name: redis
release:
chart: stable/redis
version: 5.5.5 # doesn't exist
$ landscaper apply test/redis.yaml --namespace testing2 -v --dry-run
[0000] INFO This is Landscaper v1.0.4 commit=74e77ff2b221feda63c0c4435a10812979f11ed0 tag=1.0.4
[0000] INFO Apply landscape desired state chartDir=/home/kyle/.helm dir= dryRun=true namespace=testing2 releasePrefix=testing2- verbose=true
[0000] INFO Obtain desired state from files files=[test/redis.yaml]
[0000] DEBUG Read desired state from file file=test/redis.yaml
[0000] DEBUG coalesceComponent chart=redis
[0000] DEBUG Load Chart chartRef=stable/redis
[0000] DEBUG locateChartPath chartRef=stable/redis homePath=/home/kyle/.helm name=stable/redis version=
[0000] DEBUG Look for cached local package chartPath=/tmp/landscaper/stable/redis-0.5.2.tgz
[0000] DEBUG Loaded Chart successfully chartRef=stable/redis
[0000] DEBUG desired landscaper.Component{Name:"testing2-redis", Namespace:"testing2", Release:(*landscaper.Release)(0xc420398b60), Configuration:landscaper.Configuration{"image":"bitnami/redis:3.2.8-r3", "imagePullPolicy":"IfNotPresent", "persistence":map[string]interface {}{"accessMode":"ReadWriteOnce", "enabled":true, "size":"8Gi"}, "resources":map[string]interface {}{"requests":map[string]interface {}{"cpu":"100m", "memory":"256Mi"}}, "Name":"redis", "_landscaper_metadata":map[string]interface {}{"chartrepository":"stable", "releaseversion":"5.5.5"}}, Secrets:landscaper.Secrets{}, SecretValues:landscaper.SecretValues{}}
[0000] DEBUG Desired state has been read components=1 directory=
[0000] INFO Obtain current state Helm Releases (Components) from Tiller
[0000] DEBUG listHelmReleases
[0000] DEBUG Setup Helm Client helmClientVersion=v2.3.1
[0000] DEBUG Create tiller tunnel tillerNamespace=kube-system
[0000] DEBUG Created tiller tunnel port=38350
[0000] INFO Connected to Tiller clientServerCompatible=true tillerVersion=v2.3.1
[0001] INFO Retrieved Releases (Components) landscapedComponents=0 totalReleases=0
[0001] INFO Apply desired state create=1 delete=0 update=0
[0001] INFO Create: testing2-redis
[0001] INFO Diff:
--- Current <none>
+++ Desired testing2-redis
@@ -0,0 +1,29 @@
+{
+ "name": "testing2-redis",
+ "namespace": "testing2",
+ "release": {
+ "chart": "redis",
+ "version": "5.5.5"
+ },
+ "configuration": {
+ "Name": "redis",
+ "_landscaper_metadata": {
+ "chartrepository": "stable",
+ "releaseversion": "5.5.5"
+ },
+ "image": "bitnami/redis:3.2.8-r3",
+ "imagePullPolicy": "IfNotPresent",
+ "persistence": {
+ "accessMode": "ReadWriteOnce",
+ "enabled": true,
+ "size": "8Gi"
+ },
+ "resources": {
+ "requests": {
+ "cpu": "100m",
+ "memory": "256Mi"
+ }
+ }
+ },
+ "secrets": []
+}
[0001] DEBUG Load Chart chartRef=stable/redis
[0001] DEBUG locateChartPath chartRef=stable/redis homePath=/home/kyle/.helm name=stable/redis version=
[0001] DEBUG Look for cached local package chartPath=/tmp/landscaper/stable/redis-0.5.2.tgz
[0001] DEBUG Loaded Chart successfully chartRef=stable/redis
[0001] DEBUG Create component chart=redis chartPath=/tmp/landscaper/stable/redis-0.5.2.tgz dryrun=true rawValues=_landscaper_metadata:
chartrepository: stable
releaseversion: 5.5.5
Name: redis
image: bitnami/redis:3.2.8-r3
imagePullPolicy: IfNotPresent
persistence:
accessMode: ReadWriteOnce
enabled: true
size: 8Gi
resources:
requests:
cpu: 100m
memory: 256Mi
release=testing2-redis values=map[imagePullPolicy:IfNotPresent persistence:map[enabled:true size:8Gi accessMode:ReadWriteOnce] resources:map[requests:map[cpu:100m memory:256Mi]] Name:redis _landscaper_metadata:map[chartrepository:stable releaseversion:5.5.5] image:bitnami/redis:3.2.8-r3]
[0001] INFO Applied desired state sucessfully created=1 deleted=0 updated=0
[0001] WARN Since dry-run is enabled, no actual actions have been performed
Any chance this is going to happen?
Since landscaper (and helm) make use of ~/.kube/config and really on current context to work. it's strange that landscaper does not use namespace defined in that context. Atm. the default namespace is called "default" regardless of the namespace specified in the current context.
Hello!
I'm trying to understand the added value of Landscaper
in comparison with simple helm upgrade
.
Similar to Lanscaper
, the upgrade can change a deployed release by applying the given values (-f
or --set
) to the given chart (chart reference or path to chart directory). And this can be added to your CI/CD chain to be triggered on merge.
So, what is the difference? and how do you see the combined usage of both of these solutions (if ever possible)?
Thank you,
Andrey
landscaper update does not update pods of ReplicaControllers or DaemonSets.
Ran into this while updating environment variables in a daemonset.
It looks like this is supported by helm with the --recreate-pods
argument which is a temporary workaround in place until kubernetes upstream handles it.
It seems like this option would best be supported in the landscape definition?
I'm thinking, I only want to use this argument on specific, impacted charts (e.g. logspout) especially since it does not do a soft restart right now -- helm/helm#1702
A workaround today is to build in hooks to the chart to handle recreating it's pods.
Thoughts on a plan of action?
Which creates a landscaper component template, given a chart reference. Assist with required
values (upcoming Helm feature). Show defaults. etc.
It'd be nice if you could specify which namespace to deploy charts into in a landscape definition file. Something like:
name: thing
release:
chart: repo/thing:0.1.4
version: 0.1.1
namespace: doot-system
configuration:
something: doot
Also convenient for containerised landscaper
The usage section of landscaper says "Landscaper consists of a core API and a command line interface (CLI) that consumes this API. "
Is this "core API" exposed through a REST interface?
Is there a (relatively) easy way to add/create one?
instead of a directory through --dir
. like most CLIs do. e.g.:
landscaper apply --some-flag this.yaml that.yaml mydir/* anotherdir/*
Either logrus
or "github.com/x-cray/logrus-prefixed-formatter"
changed something in a non-backward manner.
Hi,
I'm confused at "[0000] DEBUG Setup Helm Client helmClientVersion=v2.3.1", I'm using helm and tiller both v2.1.3, but why log says helmClientVersion=v2.3.1, is this mean I MUST use helm client with version 2.3.1? Thanks.
[0000] DEBUG desired landscaper.Component{Name:"example-hello-world", Namespace:"example", Release:(*landscaper.Release)(0xc420180900), Configuration:landscaper.Configuration{"message":"Hello, Landscaped world!", "sleep":1, "Name":"hello-world", "_landscaper_metadata":map[string]interface {}{"chartrepository":"devops", "releaseversion":"0.1.0"}}, Secrets:landscaper.Secrets{}, SecretValues:landscaper.SecretValues{}}
[0000] DEBUG Desired state has been read components=2 directory=example/landscape
[0000] INFO Obtain current state Helm Releases (Components) from Tiller
[0000] DEBUG listHelmReleases
[0000] DEBUG Setup Helm Client helmClientVersion=v2.3.1
[0000] DEBUG Create tiller tunnel tillerNamespace=kube-system
E0504 14:40:20.408012 7197 portforward.go:209] Unable to create listener: Error listen tcp6 [::1]:22972: bind: cannot assign requested address
[0000] DEBUG Created tiller tunnel port=22972
[0000] INFO Connected to Tiller clientServerCompatible=false tillerVersion=v2.1.3
[0000] WARN Helm and Tiller report incompatible version numbers
[0000] ERROR Loading current state failed error=rpc error: code = 2 desc = client version is incompatible
Error: rpc error: code = 2 desc = client version is incompatible
root@myserver:/tmp/landscaper$ helm version
E0504 14:40:26.246994 7211 portforward.go:209] Unable to create listener: Error listen tcp6 [::1]:34390: bind: cannot assign requested address
Client: &version.Version{SemVer:"v2.1.3", GitCommit:"5cbc48fb305ca4bf68c26eb8d2a7eb363227e973", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.1.3", GitCommit:"5cbc48fb305ca4bf68c26eb8d2a7eb363227e973", GitTreeState:"clean"}
Expected: Running landscaper apply on the same file multiple times should not result in more tiller/helm versions.
Actual: Each run detects a 'diff' when it really isn't and adds to helm/tiller versions.
Simple landscaper yaml
$ cat test/redis.yaml
name: redis
release:
chart: stable/redis
version: 0.5.2
Initial install
$ landscaper apply test/redis.yaml --namespace testing
[0000] INFO This is Landscaper v1.0.4 commit=74e77ff2b221feda63c0c4435a10812979f11ed0 tag=1.0.4
[0000] INFO Apply landscape desired state chartDir=/home/kyle/.helm dir= dryRun=false namespace=testing releasePrefix=testing- verbose=false
[0000] INFO Obtain desired state from files files=[test/redis.yaml]
[0000] INFO Obtain current state Helm Releases (Components) from Tiller
[0001] INFO Connected to Tiller clientServerCompatible=true tillerVersion=v2.3.1
[0001] INFO Retrieved Releases (Components) landscapedComponents=0 totalReleases=0
[0001] INFO Apply desired state create=1 delete=0 update=0
[0001] INFO Create: testing-redis
[0001] INFO Diff:
--- Current <none>
+++ Desired testing-redis
@@ -0,0 +1,29 @@
+{
+ "name": "testing-redis",
+ "namespace": "testing",
+ "release": {
+ "chart": "redis",
+ "version": "0.5.2"
+ },
+ "configuration": {
+ "Name": "redis",
+ "_landscaper_metadata": {
+ "chartrepository": "stable",
+ "releaseversion": "0.5.2"
+ },
+ "image": "bitnami/redis:3.2.8-r3",
+ "imagePullPolicy": "IfNotPresent",
+ "persistence": {
+ "accessMode": "ReadWriteOnce",
+ "enabled": true,
+ "size": "8Gi"
+ },
+ "resources": {
+ "requests": {
+ "cpu": "100m",
+ "memory": "256Mi"
+ }
+ }
+ },
+ "secrets": []
+}
[0002] INFO Applied desired state sucessfully created=1 deleted=0 updated=0
Running again.
$ landscaper apply test/redis.yaml --namespace testing
[0000] INFO This is Landscaper v1.0.4 commit=74e77ff2b221feda63c0c4435a10812979f11ed0 tag=1.0.4
[0000] INFO Apply landscape desired state chartDir=/home/kyle/.helm dir= dryRun=false namespace=testing releasePrefix=testing- verbose=false
[0000] INFO Obtain desired state from files files=[test/redis.yaml]
[0000] INFO Obtain current state Helm Releases (Components) from Tiller
[0000] INFO Connected to Tiller clientServerCompatible=true tillerVersion=v2.3.1
[0001] INFO Connected to Kubernetes kubernetesVersion=v1.6.2
[0001] INFO Retrieved Releases (Components) landscapedComponents=1 totalReleases=1
[0001] INFO testing-redis differs in namespace; don't update but delete + create instead
[0001] INFO Apply desired state create=0 delete=0 update=1
[0001] INFO Update: testing-redis
[0001] INFO Diff:
--- Current testing-redis
+++ Desired testing-redis
@@ -2,7 +2,7 @@
"name": "testing-redis",
"namespace": "testing",
"release": {
- "chart": "redis:0.5.2",
+ "chart": "redis",
"version": "0.5.2"
},
"configuration": {
[0001] INFO Deleting existing secrets for component component=testing-redis namespace=testing
[0001] INFO No secrets found for component component=testing-redis namespace=testing
[0002] INFO Applied desired state sucessfully created=0 deleted=0 updated=1
With -v
$ landscaper apply test/redis.yaml --namespace testing -v
[0000] INFO This is Landscaper v1.0.4 commit=74e77ff2b221feda63c0c4435a10812979f11ed0 tag=1.0.4
[0000] INFO Apply landscape desired state chartDir=/home/kyle/.helm dir= dryRun=false namespace=testing releasePrefix=testing- verbose=true
[0000] INFO Obtain desired state from files files=[test/redis.yaml]
[0000] DEBUG Read desired state from file file=test/redis.yaml
[0000] DEBUG coalesceComponent chart=redis
[0000] DEBUG Load Chart chartRef=stable/redis
[0000] DEBUG locateChartPath chartRef=stable/redis homePath=/home/kyle/.helm name=stable/redis version=
[0000] DEBUG Look for cached local package chartPath=/tmp/landscaper/stable/redis-0.5.2.tgz
[0000] DEBUG Loaded Chart successfully chartRef=stable/redis
[0000] DEBUG desired landscaper.Component{Name:"testing-redis", Namespace:"testing", Release:(*landscaper.Release)(0xc4203e14a0), Configuration:landscaper.Configuration{"Name":"redis", "_landscaper_metadata":map[string]interface {}{"chartrepository":"stable", "releaseversion":"0.5.2"}, "imagePullPolicy":"IfNotPresent", "persistence":map[string]interface {}{"enabled":true, "size":"8Gi", "accessMode":"ReadWriteOnce"}, "resources":map[string]interface {}{"requests":map[string]interface {}{"cpu":"100m", "memory":"256Mi"}}, "image":"bitnami/redis:3.2.8-r3"}, Secrets:landscaper.Secrets{}, SecretValues:landscaper.SecretValues{}}
[0000] DEBUG Desired state has been read components=1 directory=
[0000] INFO Obtain current state Helm Releases (Components) from Tiller
[0000] DEBUG listHelmReleases
[0000] DEBUG Setup Helm Client helmClientVersion=v2.3.1
[0000] DEBUG Create tiller tunnel tillerNamespace=kube-system
[0000] DEBUG Created tiller tunnel port=39116
[0000] INFO Connected to Tiller clientServerCompatible=true tillerVersion=v2.3.1
[0001] DEBUG Reading secrets for component component=testing-redis namespace=testing
[0001] DEBUG Setup Kubernetes Client
[0001] INFO Connected to Kubernetes kubernetesVersion=v1.6.2
[0001] DEBUG No secrets found for component component=testing-redis namespace=testing
[0001] INFO Retrieved Releases (Components) landscapedComponents=1 totalReleases=1
[0001] INFO testing-redis differs in namespace; don't update but delete + create instead
[0001] INFO Apply desired state create=0 delete=0 update=1
[0001] INFO Update: testing-redis
[0001] INFO Diff:
--- Current testing-redis
+++ Desired testing-redis
@@ -2,7 +2,7 @@
"name": "testing-redis",
"namespace": "testing",
"release": {
- "chart": "redis:0.5.2",
+ "chart": "redis",
"version": "0.5.2"
},
"configuration": {
[0001] DEBUG Load Chart chartRef=stable/redis
[0001] DEBUG locateChartPath chartRef=stable/redis homePath=/home/kyle/.helm name=stable/redis version=
[0001] DEBUG Look for cached local package chartPath=/tmp/landscaper/stable/redis-0.5.2.tgz
[0001] DEBUG Loaded Chart successfully chartRef=stable/redis
[0001] INFO Deleting existing secrets for component component=testing-redis namespace=testing
[0001] INFO No secrets found for component component=testing-redis namespace=testing
[0001] DEBUG Update component chart=redis chartPath=/tmp/landscaper/stable/redis-0.5.2.tgz dryrun=false release=testing-redis values=map[image:bitnami/redis:3.2.8-r3 Name:redis _landscaper_metadata:map[chartrepository:stable releaseversion:0.5.2] imagePullPolicy:IfNotPresent persistence:map[accessMode:ReadWriteOnce enabled:true size:8Gi] resources:map[requests:map[cpu:100m memory:256Mi]]]
[0002] INFO Applied desired state sucessfully created=0 deleted=0 updated=1
And kubectl goodness of the configmaps for tiller
$ kubectl -n kube-system get configmaps | grep testing-
testing-redis.v1 1 6m
testing-redis.v2 1 6m
testing-redis.v3 1 3m
Since the release itself didn't change, but only the k8s secret map. Use a delete+create combo instead to force it.
Check for environment variables for any secrets to avoid deploying with missing configurations.
In a more descriptive, less mysterious fashion
provide the ability to not use a cached chart in the event the cached copy is corrupted or re-deploying the same version.
Hi,
Can you upload binary files to releases page instead of source code? I'm having trouble to build ... Thanks.
[INFO] --> Exporting golang.org/x/net
[INFO] --> Exporting golang.org/x/oauth2
[INFO] --> Exporting gopkg.in/validator.v2
[INFO] --> Exporting gopkg.in/yaml.v2
[INFO] --> Exporting k8s.io/kubernetes
[INFO] --> Exporting cloud.google.com/go
[INFO] --> Exporting golang.org/x/text
[INFO] --> Exporting google.golang.org/grpc
[INFO] Replacing existing vendor dependencies
[ERROR] Unable to export dependencies to vendor directory: symlink ../../../contrib/init/sysvinit-debian/docker.default /data/gowork/src/github.com/eneco/landscaper/vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.docker.default: operation not supported
Makefile:21: recipe for target 'bootstrap' failed
make: *** [bootstrap] Error 1
root@ubuntu16:/data/gowork/src/github.com/eneco/landscaper# ll /data/gowork/src/github.com/eneco/landscaper/vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.docker.default
ls: cannot access '/data/gowork/src/github.com/eneco/landscaper/vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.docker.default': No such file or directory
root@ubuntu16:/data/gowork/src/github.com/eneco/landscaper/vendor/github.com/docker/docker/hack/make/.build-deb# ll
total 13
drwxr-xr-x 2 root root 0 Apr 6 23:25 ./
drwxr-xr-x 2 root root 8192 Apr 6 23:25 ../
-rwxr-xr-x 1 root root 2 Apr 6 23:25 compat*
-rwxr-xr-x 1 root root 1238 Apr 6 23:25 control*
Read a current state from a cluster and write it to files. These files will equal the desired state used to generate the landscape.
by delete/create instead of update?
For example in a Helm chart, we have "REQUIRED", can we check that we have values for this in the landscaper?
acceptance
is an odd default.
What is the release.version used for in a component definition?
release:
version: 0.1.0
it is an unused artefact
This is my state file for Datadog Chart:
name: datadog
release:
chart: stable/datadog:0.3.0
version: 0.3.0
configuration:
# Default values for datadog.
image:
repository: datadog/docker-dd-agent
tag: latest
pullPolicy: IfNotPresent
datadog:
## You'll need to set this to your Datadog API key before the agent will run.
## ref: https://app.datadoghq.com/account/settings#agent/kubernetes
##
apiKey: ""
## Set logging verbosity.
## ref: https://github.com/DataDog/docker-dd-agent#environment-variables
##
logLevel: WARNING
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 256m
memory: 512Mi
secrets:
- api-key
and this is how run landscraper
API_KEY=343242342342 landscaper apply --dir charts --dry-run --namespace default
Unfortunately the secret API_KEY is not applied. Any idea?
Following the philosophy of delete before create, the update should be done before create as well.
Convenient if you want to test run something you're working on and ignore the rest of the landscape.
Superset of #42. I would love to have pluggable sources for secrets other than environment variables, such as a local file, Hashicorp's Vault, other remote K/V stores like Etcd/Consul, etc. Of course, you could wire up basically any of what I've mentioned to populate env vars with a little glue code, often surprisingly little. But env vars have some trade-offs that prevent them from being some user's first choice for sensitive data, myself included.
Workaround replaces an update with a delete
+create
. In dry-run, the delete
is dry-ran, and the dry-run create
fails since the not-really-deleted component already exists.
It would be nice to be able to use the --set flag with similar functionality to the Helm --set flag.
...such as supporting a customizable prefix (secret named foo-bar
becomes FOO_BAR
by default, or optionally PREFIX_FOO_BAR
).
It would be great to colorize the diff output, so removed lines are red and added lines are green.
When displaying a diff, it would be nice to optionally show the verbose output from helm install.
This would let you see exactly what kubernetes resources are going to be created.
Components are uniquely identified by name. Current implementation consists of traversals to look up and x-ref Components by name. Behaviour is effectively a Map implemented on top of slices. Map is more natural, more LoC compact and more big-O time efficient.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.