Giter Club home page Giter Club logo

kqueen's Introduction

KQueen - Kubernetes cluster manager

https://travis-ci.org/Mirantis/kqueen.svg?branch=master https://coveralls.io/repos/github/Mirantis/kqueen/badge.svg?branch=master https://readthedocs.org/projects/kqueen/badge/?version=master

Overview

More information about KQueen Architecture and use cases is described in RATIONALE file.

Requirements

  • Python v3.6 and higher.
  • Pip v3 and higher.
  • Docker stable release (v17.03 and higher is preferable).
  • Docker-compose stable release (v1.16.0 and higher is preferable).

Demo environment

  • Make sure you can reach Jenkins server defined in JENKINS_API_URL variable in file kqueen/config/prod.py.

  • Run these commands to run Kqueen API and UI in containers.

    docker-compose -f docker-compose.yml -f docker-compose.demo.yml up
    

    or with mounted etcd data directory:

    docker-compose -f docker-compose.etcd-volume.yml -f docker-compose.demo.yml up
    
  • You can login using user admin and password default. Default username and password can be changed in docker-compose.demo.yml file before first start of API.

  • Navigate to UI

Development

  • Install dependencies

    # Debian/Ubuntu
    sudo apt-get install libsasl2-dev python-dev libldap2-dev libssl-dev
    
    # RedHat/CentOS:
    sudo yum install python-devel openldap-devel
    
  • Prepare python virtual environment

    python -m ensurepip --default-pip
    pip install --user pipenv
    pipenv --python 3.6
    pipenv install --dev
    
    pipenv shell
    
  • Start docker container with etcd storage

    docker-compose up -d
    
  • Initialize kqueen db: add admin user with default password

    ./bootstrap_admin.py DemoOrg demoorg admin default
    
  • Create directories to store Kqueen data and log files

    mkdir - m 666 /var/log/kqueen-api
    mkdir - m 666 /opt/kqueen
  • Install kubespray or provide path to the existing installation by specifying KS_KUBESPRAY_PATH in the config file

git clone -b v2.5.0 https://github.com/kubernetes-incubator/kubespray.git && \
pip install -r kubespray/requirements.txt
  • You can start KQueen API service directly

    kqueen &
    chrome --new-tab http://127.0.0.1:5000/api/docs/
    
  • Prepare kubernetes config file

Kubernetes configuration file that describes existing cluster can be used in Kqueen. Rename it with kubernetes_remote and place to the root of the project. For test purposes this file can be empty, but should be added manually.

How-to's

  • Clean etcd storage after previous runs

    etcdctl rm --recursive /kqueen
    
  • Add admin user, organization, mock clusters and provisioners to etcd storage at once, execute the following

    ./devenv.py
    
  • To add a single admin user with default password within associated DemoOrg organization in provided demoorg namespace, execute the following

    ./bootstrap_admin.py DemoOrg demoorg admin default
    
  • Test access token. curl, jq should be installed in your system

    TOKEN=$(curl -s -H "Content-Type: application/json" --data '{"username":"admin","password":"default"}' -X POST localhost:5000/api/v1/auth | jq -r '.access_token')
    echo $TOKEN
    curl -H "Authorization: Bearer $TOKEN" localhost:5000/api/v1/clusters
    
  • Set up flask shell for manual testing and debugging

    export FLASK_APP=kqueen.server
    export prometheus_multiproc_dir=$(mktemp -d)
    flask shell
    
  • Update Docker image with code changes

There are two ways to test development changes. First is automatic: create a separate branch and push PR, then TravisCI build image and push it on Docker Hub automatically. Second one is just rebuild kqueen api-image locally:

docker build -t kqueen/api:your_tag .

Configuration

We load configuration from file config/dev.py by default and this can be configured by KQUEEN_CONFIG_FILE environment variable. Any environment variable matching name KQUEEN_* will be loaded and saved to configuration.

Documentation

Full documentation can be found at kqueen.readthedocs.io.

API reference is defined at api.yml and Swagger UI is available at <kqueen_api_url>/api/docs

DEMOs

Generic KQueen Overview

https://img.youtube.com/vi/PCAwCxPQc2A/0.jpg

AKS (Azure) in KQueen

https://img.youtube.com/vi/xHydnJGcs2k/0.jpg

Network policy management in KQueen

The following video provides an overview on how to manage the Calico network policy for a Kubernetes cluster provisioned with Google Kubernetes Engine using KQueen.

https://img.youtube.com/vi/MYXFI75Fm10/0.jpg

kqueen's People

Contributors

cznewt avatar epcim avatar fpytloun avatar jakubjosef avatar katyafervent avatar mzlatkova avatar naumvd95 avatar pupapaik avatar ruzickap avatar samos123 avatar tomkukral avatar vijaysamanuri avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kqueen's Issues

Global configuration

Implement global configuration module for app:

  • loadable outside of context
  • loadable in test (with different settings)

API failure

Verify this scenario:

  1. create resources (namespaced and global)
  2. delete all resources
  3. run tests - we expect to get api error
kqueen_1       | [2017-12-04 14:12:21 +0000] [21] [ERROR] Error handling request /api/v1/provisioners
kqueen_1       | Traceback (most recent call last):
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/gunicorn/workers/sync.py", line 135, in handle
kqueen_1       |     self.handle_request(listener, req, client, addr)
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/gunicorn/workers/sync.py", line 176, in handle_request
kqueen_1       |     respiter = self.wsgi(environ, resp.start_response)
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1997, in __call__
kqueen_1       |     return self.wsgi_app(environ, start_response)
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1985, in wsgi_app
kqueen_1       |     response = self.handle_exception(e)
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1540, in handle_exception
kqueen_1       |     reraise(exc_type, exc_value, tb)
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
kqueen_1       |     raise value
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
kqueen_1       |     response = self.full_dispatch_request()
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1614, in full_dispatch_request
kqueen_1       |     rv = self.handle_user_exception(e)
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1517, in handle_user_exception
kqueen_1       |     reraise(exc_type, exc_value, tb)
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
kqueen_1       |     raise value
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
kqueen_1       |     rv = self.dispatch_request()
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
kqueen_1       |     return self.view_functions[rule.endpoint](**req.view_args)
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/flask/views.py", line 84, in view
kqueen_1       |     return self.dispatch_request(*args, **kwargs)
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/kqueen/blueprints/api/generic_views.py", line 25, in dispatch_request
kqueen_1       |     output = self.get_content(*args, **kwargs)
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/kqueen/blueprints/api/generic_views.py", line 90, in get_content
kqueen_1       |     return list(self.get_class().list(namespace, return_objects=True).values())
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/kqueen/storages/etcd.py", line 365, in list
kqueen_1       |     output[result.key.replace(key, '')] = cls.deserialize(result.value, namespace=namespace)
kqueen_1       |   File "/usr/local/lib/python3.6/site-packages/kqueen/storages/etcd.py", line 401, in deserialize
kqueen_1       |     toplevel = json.loads(serialized)
kqueen_1       |   File "/usr/local/lib/python3.6/json/__init__.py", line 348, in loads
kqueen_1       |     'not {!r}'.format(s.__class__.__name__))
kqueen_1       | TypeError: the JSON object must be str, bytes or bytearray, not 'NoneType'
``

Add resources to API

Itemplement these API calls:

  • Cluster create

  • Provisioner list

  • Provisioner get

  • Organization - list/detail/create/delete

  • User - list/detail/create/delete

cc @atengler

add unique attribute

  • add unique=True and check these fields are unique across all objects

Will be used for:

  • User - username
  • Organization - namespace

Jenkins cluster size

Add minion count parameter for Jenkins engine.

We need to have a way to specify number of minions.

refs: #98

Detail for non-existing cluster

User story:

  1. Add Kubernetes cluster using manual provisioner
  2. Delete cluster
  3. Try to display cluster details

API should return reasonable response and well commented error.

Update storing credentials

We currently have SecretField but it isn't sufficient. There are two requirements:

  • PasswordField - only hash of value is stored and field have verify method to check password is same.
  • secret=True parameter for any field. These field will use symetrical encryption before saving the value to backend.

Add requied value for field.

We need to have option required=True for Fields to indicate these fields are required in model.

Validation method will loop over all fields and report missing fields.

Apply resource file

Add function to apply yaml file to the cluster.

User story:
I'm administrator and I'd like to apply some YAML file with resource to my cluster.

Add list of images

Provide list of used images:

  • list images from deployments
  • list images from nodes

Add addons list

We will list services, filter it according to annotations and display in grid.

kind: Service
apiVersion: v1
metadata:
  name: monocular
  annotations:
    kqueen/name: Monocular
    kqueen/icon: https://www.modarmory.com/wp-content/uploads/2014/05/night-vision-monocular-icon.png
    kqueen/link: http://monocular-load-balancer-or-ingress-url
spec:
  selector:
    app: MyApp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376

Cluster scaling

Implement scaling method for Provisioner class. Requirements:

  • scaling up
  • scaling down with posiblity to select node to evict
  • scaling down can be invoked with hard=True and this mode will skip node draining

Implementation of methods in provisioners isn't a part of this issue. We just want to desing it and prepare methods. All of scaling methods are optional because some provisioners (e.g. Manual) lack scaling support.

add RelationField

Add new field type: RelationField and it will be used to link other objects.

Serialized value: ModelName:objectid, for example Cluster:203c50d6-3d09-4789-8b8b-1ecb00814436

Update loadbalancer links

Change behavior of displaying links to load balancers

  • show full URL on click - we need to copy it sometimes
  • use http:// for ports 80, 443, 8080
  • use https:// for ports 443, 4430, 6443

Error in topology data

127.0.0.1 - - [18/Oct/2017 17:11:21] "GET /api/v1/clusters/3f4faf00-10cd-4091-9ec3-a88d3a2ec5e5/topology-data HTTP/1.1" 500 -
Traceback (most recent call last):
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1997, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1985, in wsgi_app
    response = self.handle_exception(e)
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1540, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/tom/src/kqueen/kqueen/blueprints/api/views.py", line 94, in cluster_topology_data
    return jsonify(obj.topology_data())
  File "/home/tom/src/kqueen/kqueen/models.py", line 200, in topology_data
    'target': service_select_app_2_uid[resource['metadata']['labels']['app']]

Research on Open Broker API

Prepare draft for OBA implementation. Probably the best way is to have another blueprint. Some models may need to be slightly adjusted.

Add test for manual engine

  • kubeconfig file is empty
  • kubeconfig file isn't valid json/yaml
  • load json kubeconfig
  • load yaml kubeconfig

Add remote_class to RelationField

Add linked_class attribute (required) and change serialized format of RelationField from ModelName:id to id

  • check namespace of foreign object

Return token with user

Return user object together with access token.

{                   
  "access_token": "e...uxQ",
  "user": {
  ... user.get_dict()
  }
}

This flask-jwt method shoud be changed:


def _default_auth_response_handler(access_token, identity):
    return jsonify({'access_token': access_token.decode('utf-8')})

Raise on missing secret

We currently need secret to store all sensitive data and we need to raise error when starting without this option.

Fix access to Kubernetes

Some clusters can't be accessed by kubeapi.

DEBUG:kqueen.storages.etcd:Model __init__
DEBUG:kqueen.kubeapi:Initialized KubernetesAPI for cluster <7922350f-03e8-4db1-abba-d0613177ffa3>
/tmp/kubernetes
2017-10-03 23:34:42,355 WARNING Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7fe0272f6f98>: Failed to establish a new connection: [Errno -2] Name or service not known',)': /api/v1/nodes
2017-10-03 23:34:42,355 WARNING Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7fe0272f6f98>: Failed to establish a new connection: [Errno -2] Name or service not known',)': /api/v1/nodes
WARNING:urllib3.connectionpool:Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7fe0272f6f98>: Failed to establish a new connection: [Errno -2] Name or service not known',)': /api/v1/nodes
2017-10-03 23:34:42,789 WARNING Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7fe026f92828>: Failed to establish a new connection: [Errno -2] Name or service not known',)': /api/v1/nodes
2017-10-03 23:34:42,789 WARNING Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7fe026f92828>: Failed to establish a new connection: [Errno -2] Name or service not known',)': /api/v1/nodes
WARNING:urllib3.connectionpool:Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7fe026f92828>: Failed to establish a new connection: [Errno -2] Name or service not known',)': /api/v1/nodes
2017-10-03 23:34:43,226 WARNING Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7fe026f92e10>: Failed to establish a new connection: [Errno -2] Name or service not known',)': /api/v1/nodes
2017-10-03 23:34:43,226 WARNING Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7fe026f92e10>: Failed to establish a new connection: [Errno -2] Name or service not known',)': /api/v1/nodes
WARNING:urllib3.connectionpool:Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7fe026f92e10>: Failed to establish a new connection: [Errno -2] Name or service not known',)': /api/v1/nodes
INFO:werkzeug:127.0.0.1 - - [03/Oct/2017 23:34:43] "GET /ui/clusters/7922350f-03e8-4db1-abba-d0613177ffa3/detail HTTP/1.1" 200 -

Failed serialization of empty JSONField

Traceback (most recent call last):
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1997, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1985, in wsgi_app
    response = self.handle_exception(e)
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1540, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/tom/.venvs/kqueen/lib/python3.6/site-packages/flask/views.py", line 84, in view
    return self.dispatch_request(*args, **kwargs)
  File "/home/tom/src/kqueen/kqueen/blueprints/api/generic_views.py", line 76, in dispatch_request
    self.set_object(*args, **kwargs)
  File "/home/tom/src/kqueen/kqueen/blueprints/api/generic_views.py", line 146, in set_object
    self.obj = list(self.get_class().list(namespace, return_objects=True).values())
  File "/home/tom/src/kqueen/kqueen/storages/etcd.py", line 463, in list
    output[result.key.replace(key, '')] = cls.deserialize(result.value, namespace=namespace)
  File "/home/tom/src/kqueen/kqueen/storages/etcd.py", line 505, in deserialize
    field_object.decrypt(toplevel[field_name], **kwargs)
  File "/home/tom/src/kqueen/kqueen/storages/etcd.py", line 154, in decrypt
    return self.deserialize(crypted, **kwargs)
  File "/home/tom/src/kqueen/kqueen/storages/etcd.py", line 300, in deserialize
    obj = obj_class.load(kwargs.get('namespace'), object_id)
  File "/home/tom/src/kqueen/kqueen/storages/etcd.py", line 482, in load
    return cls.deserialize(value, key=key, namespace=namespace)
  File "/home/tom/src/kqueen/kqueen/storages/etcd.py", line 505, in deserialize
    field_object.decrypt(toplevel[field_name], **kwargs)
  File "/home/tom/src/kqueen/kqueen/storages/etcd.py", line 165, in decrypt
    self.deserialize(serialized, **kwargs)
  File "/home/tom/src/kqueen/kqueen/storages/etcd.py", line 93, in deserialize
    self.set_value(serialized, **kwargs)
  File "/home/tom/src/kqueen/kqueen/storages/etcd.py", line 262, in set_value
    self.value = json.loads(value)
  File "/usr/lib64/python3.6/json/__init__.py", line 354, in loads
    return _default_decoder.decode(s)
  File "/usr/lib64/python3.6/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib64/python3.6/json/decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Log model

Create Log model so we can create objects which tracks user actions. We could then for example list all actions (create, delete, update) done in Organization/by specific user.

Manual deployer

Finish work on manual deployer.

This deployer works this way:

  1. Cluster is created by any external method
  2. kubeconfig is uploaded during creation of Cluster object
  3. Manually deployed cluster can be monitored in UI same way as native one

DoD:

  • Cluster can be added via UI
  • kubeconfig file is saved into Cluster instance during creating

Namespaced resources

All resources (except User and Organization) will be namespaced.

Implement namespacing with etcd in similar way as Kubernetes is using.

Demo bootstrap

Prepare & verify bootstrap instructions for demo scenario.

MVP version

For MVP version we want to have:

  • described deployment (docker-compose and virtualenv)
  • list of clusters
  • cluster detail
  • cluster status (nodes, services (per namespace), used images,
  • cluster create (with default provisioner options)

User story:

I'll send request to create cluster, cluster is created and I can get details and endpoints.

Encrypted property

Add encrypted=True property to all fields.
These field will be encrypted before serialization and decrypted after serialization.
It means value will be stored in encrypted format.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.