Coder Social home page Coder Social logo

smi-adapter-istio's People

Contributors

alban avatar bridgetkromhout avatar grampelberg avatar idvoretskyi avatar lachie83 avatar mkosieradzki avatar pratap-bhaskar avatar rinormaloku avatar slack avatar stefanprodan avatar subashd avatar surajssd avatar u5surf 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

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

smi-adapter-istio's Issues

move smi repos to another org?

We could move the SMI related repos to their own github org. I currently have github.com/service-mesh-interface and github.com/servicemeshinterface. It'd be nice to have everything in one logical place dedicated to SMI to help create a community around that. It's easier from a management perspective to keep it all in deislabs though.

Thoughts? Any other pros/cons people can think of?

weight logic clarification

Istio only talks about weights as whole numbers (0-100) that indicate percentage traffic and in the documentation never mentions the milli notation ("1000m"). The docs also state that the weights should add up to 100.

Is there a reason to support the milli notation? or should we switch to only supporting whole numbers?

smi-adapter-smi installation fails with Istio 1.7.0

Hello team,
Trying to install smi-adapter-smi with Istio 1.7.0 and onwards consistenly fails due to the error "no matches for kind \"ServiceRoleBinding\" in version \"rbac.istio.io/v1alpha1\".

$ kubectl get pods -n istio-system                                                                                                                                                                                                          
NAME                                    READY   STATUS    RESTARTS   AGE
istio-ingressgateway-78c77dbd6b-89tw9   1/1     Running   0          103s
istiod-bcbdd4bdc-9nxp4                  1/1     Running   0          2m4s
kiali-64f76f6c9b-wt56w                  1/1     Running   0          103s
smi-adapter-istio-54b7c99755-pvhx9      0/1     Error     3          63s

Logs from the failing smi-adapter-smi pod:

$ kubectl logs smi-adapter-istio-54b7c99755-pvhx9 -n istio-system
{"level":"info","ts":1600429116.0237238,"logger":"cmd","msg":"Go Version: go1.12.17"}
{"level":"info","ts":1600429116.0237808,"logger":"cmd","msg":"Go OS/Arch: linux/amd64"}
{"level":"info","ts":1600429116.0237858,"logger":"cmd","msg":"Version of operator-sdk: v0.10.0"}
{"level":"info","ts":1600429116.023999,"logger":"leader","msg":"Trying to become the leader."}
{"level":"info","ts":1600429116.100995,"logger":"leader","msg":"Found existing lock with my name. I was likely restarted."}
{"level":"info","ts":1600429116.1010294,"logger":"leader","msg":"Continuing as the leader."}
{"level":"info","ts":1600429116.1434884,"logger":"cmd","msg":"Registering Components."}
{"level":"info","ts":1600429116.1445546,"logger":"kubebuilder.controller","msg":"Starting EventSource","controller":"trafficsplit-controller","source":"kind source: /, Kind="}
{"level":"info","ts":1600429116.1447358,"logger":"kubebuilder.controller","msg":"Starting EventSource","controller":"trafficsplit-controller","source":"kind source: /, Kind="}
{"level":"info","ts":1600429116.1448414,"logger":"kubebuilder.controller","msg":"Starting EventSource","controller":"traffictarget-controller","source":"kind source: /, Kind="}
{"level":"info","ts":1600429116.1449068,"logger":"kubebuilder.controller","msg":"Starting EventSource","controller":"traffictarget-controller","source":"kind source: /, Kind="}
{"level":"error","ts":1600429116.1785803,"logger":"kubebuilder.source","msg":"if kind is a CRD, it should be installed before calling Start","kind":"ServiceRoleBinding.rbac.istio.io","error":"no matches for kind \"ServiceRoleBinding\" in version \"rbac.istio.io/v1alpha1\"","stacktrace":"github.com/servicemeshinterface/smi-adapter-istio/vendor/github.com/go-logr/zapr.(*zapLogger).Error\n\tsmi-adapter-istio/vendor/github.com/go-logr/zapr/zapr.go:128\ngithub.com/servicemeshinterface/smi-adapter-istio/vendor/sigs.k8s.io/controller-runtime/pkg/source.(*Kind).Start\n\tsmi-adapter-istio/vendor/sigs.k8s.io/controller-runtime/pkg/source/source.go:89\ngithub.com/servicemeshinterface/smi-adapter-istio/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Watch\n\tsmi-adapter-istio/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:122\ngithub.com/servicemeshinterface/smi-adapter-istio/vendor/github.com/deislabs/smi-adapter-istio/pkg/controller/traffictarget.add\n\tsmi-adapter-istio/vendor/github.com/deislabs/smi-adapter-istio/pkg/controller/traffictarget/traffictarget_controller.go:60\ngithub.com/servicemeshinterface/smi-adapter-istio/vendor/github.com/deislabs/smi-adapter-istio/pkg/controller/traffictarget.Add\n\tsmi-adapter-istio/vendor/github.com/deislabs/smi-adapter-istio/pkg/controller/traffictarget/traffictarget_controller.go:33\ngithub.com/servicemeshinterface/smi-adapter-istio/vendor/github.com/deislabs/smi-adapter-istio/pkg/controller.AddToManager\n\tsmi-adapter-istio/vendor/github.com/deislabs/smi-adapter-istio/pkg/controller/controller.go:13\nmain.main\n\tsmi-adapter-istio/cmd/manager/main.go:106\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:200"}
{"level":"error","ts":1600429116.1786854,"logger":"cmd","msg":"","error":"no matches for kind \"ServiceRoleBinding\" in version \"rbac.istio.io/v1alpha1\"","stacktrace":"github.com/servicemeshinterface/smi-adapter-istio/vendor/github.com/go-logr/zapr.(*zapLogger).Error\n\tsmi-adapter-istio/vendor/github.com/go-logr/zapr/zapr.go:128\nmain.main\n\tsmi-adapter-istio/cmd/manager/main.go:107\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:200"}

Does the team has any plans to update smi-adapter-istio to latest Istio releases?

e2e test for TrafficAccess

I've verified manually that the TrafficAccess example works with the latest from master.

An e2e should include deploying two services and verifying that they cannot talk to each other, deploying the traffic access configuration and verifying that can talk to each other.

remove vendor/ directory and switch to using make bootstrap

Currently, we're checking in the vendor directory. We can remove the vendor directory from git if we update the dep files and then rely entirely on make bootstrap target in the Makefile to install dependencies locally. This will allow us to slim down our repo. It'll also help us keep track of the versions of packages we're using cleanly.

See the helm repo for an example.

add information about version support

For users, we should state which versions of Istio/Kubernetes we support.
For developers, we should also state which version of operator-sdk and go are needed to build this project.

Implementing HTTPRouteGroup and TrafficTarget for Istio

For the given SMI configs:

apiVersion: specs.smi-spec.io/v1alpha1
kind: HTTPRouteGroup
metadata:
  name: api-service-routes
matches:
- name: api
  pathRegex: /api
  methods: ["*"]
- name: metrics
  pathRegex: /metrics
  methods: ["GET"]

---
kind: TrafficTarget
apiVersion: access.smi-spec.io/v1alpha1
metadata:
  name: api-service-metrics
  namespace: default
destination:
  kind: ServiceAccount
  name: api-service
  namespace: default
specs:
- kind: HTTPRouteGroup
  name: api-service-routes
  matches:
  - metrics
sources:
- kind: ServiceAccount
  name: prometheus
  namespace: default

---
kind: TrafficTarget
apiVersion: access.smi-spec.io/v1alpha1
metadata:
  name: api-service-api
  namespace: default
destination:
  kind: ServiceAccount
  name: api-service
  namespace: default
  port: 8080
specs:
- kind: HTTPRouteGroup
  name: api-service-routes
  matches:
  - api
sources:
- kind: ServiceAccount
  name: website-service
  namespace: default
- kind: ServiceAccount
  name: payments-service
  namespace: default

From what I understand can be converted to following istio configs:

---
apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: api-service-metrics
  namespace: default
spec:
  rules:
  - services: ["*"]
    paths: ["/metrics"] # from HTTPRouteGroup.matches.pathRegex
    methods: ["GET"]    # from HTTPRouteGroup.matches.methods
    constraints:
    - key: "destination.user"
      values: ["api-service"]       # from TrafficTarget.destination.name
    - key: "destination.namespace"
      values: ["default"]           # from TrafficTarget.destination.namespace
---
apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: api-service-metrics
  namespace: default
spec:
  subjects:
  - user: "cluster.local/ns/default/sa/prometheus"   # from TrafficTarget.sources.name
  roleRef:
    kind: ServiceRole
    name: "api-service-metrics"


---
apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: api-service-api
  namespace: default
spec:
  rules:
  - services: ["*"]
    paths: ["/api"]     # from HTTPRouteGroup.matches.pathRegex
    methods: ["*"]      # from HTTPRouteGroup.matches.methods
    constraints:
    - key: "destination.port"
      values: ["8080"]              # from TrafficTarget.destination.port
    - key: "destination.user"
      values: ["api-service"]       # from TrafficTarget.destination.name
    - key: "destination.namespace"
      values: ["default"]           # from TrafficTarget.destination.namespace
---
apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: api-service-api
  namespace: default
spec:
  subjects:
  - user: "cluster.local/ns/default/sa/website-service"     # from TrafficTarget.sources.name
  - user: "cluster.local/ns/default/sa/payments-service"    # from TrafficTarget.sources.name
  roleRef:
    kind: ServiceRole
    name: "api-service-api"

How is this conversion done?

  • Here pair of Istio ServiceRole and Istio ServiceRoleBinding is created with same name based on each SMI TrafficTarget. For the SMI HTTPRouteGroup referred in SMI TrafficTarget.specs.kind a corresponding Istio ServiceRole is created.

  • For each SMI TrafficTarget.specs[*].matches.pathRegex & TrafficTarget.specs[*].matches.methods list the entries in corresponding Istio ServiceRole.spec.rules.paths & ServiceRole.spec.rules.methods respectively will be populated.

  • For each SMI TrafficTarget.sources the service account names are just put into Istio ServiceRoleBinding.spec.subjects.

  • For each SMI TrafficTarget.destination.name the entry is added to Istio ServiceRole.spec.rules.constraints with key as destination.user and similarly for the namespace and port information is added.

TrafficTarget no longer work with newer Istio releases

Hello team,
Attempting to setup BookInfo sample app with TrafficTarget according to steps as in this guide based on newer versions of Istio do not turn up successful. In this guide, it is referring to YAML specs go back to Istio 1.1 which do not exist with latest versions. The Istio version we are using is "1.6.8".

Acording to this note, v1alpha1 RBAC policy has been deprecated since Istio 1.4.
Therefore, when trying to deploy Traffic Access Control and Traffic Spec, their handling is ignored by Istio and accordingly the access control is not applied as expected.

Can you please confirm if this is a known issue? Any idea what Istio version is currently supported by smi-adapter-istio?
Also, do you have plans to update TrafficTarget to work with Istio AuthorizationPolicy?

add using smi-adapter-istio to smi-spec.io?

There is a website/landing page at smi-spec.io that talks about the spec but doesn't mention any implementations. Do we want to start adding links to the website around how to use SMI with Istio and other providers?

Failed to create smi-adapter-istio crds on Kubernetes v1.22

I failed to create smi-adapter-istio crds on Kubernetes v1.22 with command:

$ kubectl apply -f https://raw.githubusercontent.com/servicemeshinterface/smi-adapter-istio/master/deploy/crds/crds.yaml
unable to recognize "https://raw.githubusercontent.com/servicemeshinterface/smi-adapter-istio/master/deploy/crds/crds.yaml": no matches for kind "CustomResourceDefinition" in version "apiextensions.k8s.io/v1beta1"
unable to recognize "https://raw.githubusercontent.com/servicemeshinterface/smi-adapter-istio/master/deploy/crds/crds.yaml": no matches for kind "CustomResourceDefinition" in version "apiextensions.k8s.io/v1beta1"
unable to recognize "https://raw.githubusercontent.com/servicemeshinterface/smi-adapter-istio/master/deploy/crds/crds.yaml": no matches for kind "CustomResourceDefinition" in version "apiextensions.k8s.io/v1beta1"

The root cause is that apiextensions.k8s.io/v1beata1 was deprecated in k8s v1.22.0 version. So the api version and spec should be updated in deploy/crds/crds.yaml.

translated traffic targets don't work before istio-1.4 due to istio bug

Trying to follow the example here: https://github.com/deislabs/smi-adapter-istio/tree/master/docs/smi-traffictarget

I have deployed istio with SMI and an mtls MeshPolicy. I set up ingress and to start I have no destination rules, service roles, service role bindings, http route groups, traffic targets, etc.

image

Now I apply the ClusterRbacConfig to set up deny rules everywhere:

apiVersion: rbac.istio.io/v1alpha1
kind: ClusterRbacConfig
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"rbac.istio.io/v1alpha1","kind":"ClusterRbacConfig","metadata":{"annotations":{},"name":"default"},"spec":{"mode":"ON"}}
  creationTimestamp: 2019-10-30T17:52:51Z
  generation: 1
  name: default
  resourceVersion: "23019"
  selfLink: /apis/rbac.istio.io/v1alpha1/clusterrbacconfigs/default
  uid: 17dac909-fb3e-11e9-867e-42010a800172
spec:
  mode: "ON"

image

Now I'll create the productpage viewer service role and binding to make productpage load again, with no data from details, reviews, or services:

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: productpage-viewer
  namespace: bookinfo
spec:
  rules:
    - services: ["productpage.bookinfo.svc.cluster.local"]
      methods: ["GET"]
---
apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: bind-productpage-viewer
  namespace: bookinfo
spec:
  subjects:
    - user: "*"
  roleRef:
    kind: ServiceRole
    name: "productpage-viewer"

So far so good:
image

Now I want to enable a portion of the application with SMI. So I create a single http route group and traffic target to enable product page to talk to the details service and populate the left hand side here:

---
apiVersion: specs.smi-spec.io/v1alpha1
kind: HTTPRouteGroup
metadata:
  name: bookinfo-allowed-paths
  namespace: bookinfo
matches:
- name: api
  pathRegex: ""
  methods: ["*"]
---
kind: TrafficTarget
apiVersion: access.smi-spec.io/v1alpha1
metadata:
  name: productpage-v1-details-v1
  namespace: bookinfo
destination:
  kind: ServiceAccount
  name: details-v1
  namespace: bookinfo
specs:
  - kind: HTTPRouteGroup
    name: bookinfo-allowed-paths
    matches:
      - api
sources:
  - kind: ServiceAccount
    name: productpage-v1
    namespace: bookinfo

Now I expect productpage to be able to load details, but fail to load ratings or reviews. However, it appears the reviews are loaded in addition to details, and only the ratings service is unavailable:

image

I looked and confirmed only one service role and role binding were added:

[13:55:49] rick@Ricks-MacBook-Pro-2:~/code2/valet-config$ kubectl get servicerole -n bookinfo
NAME                        AGE
productpage-v1-details-v1   1m
productpage-viewer          3m
[13:57:05] rick@Ricks-MacBook-Pro-2:~/code2/valet-config$ kubectl get servicerolebinding -n bookinfo
NAME                        REFERENCE                   AGE
bind-productpage-viewer     productpage-viewer          3m
productpage-v1-details-v1   productpage-v1-details-v1   1m
apiVersion: rbac.istio.io/v1alpha1
kind: ServiceRole
metadata:
  creationTimestamp: 2019-10-30T17:55:49Z
  generation: 1
  name: productpage-v1-details-v1
  namespace: bookinfo
  ownerReferences:
  - apiVersion: access.smi-spec.io/v1alpha1
    blockOwnerDeletion: true
    controller: true
    kind: TrafficTarget
    name: productpage-v1-details-v1
    uid: 81bef9a7-fb3e-11e9-867e-42010a800172
  resourceVersion: "23950"
  selfLink: /apis/rbac.istio.io/v1alpha1/namespaces/bookinfo/serviceroles/productpage-v1-details-v1
  uid: 81df089b-fb3e-11e9-867e-42010a800172
spec:
  rules:
  - constraints:
    - key: destination.user
      values:
      - details-v1
    - key: destination.namespace
      values:
      - bookinfo
    methods:
    - '*'
    paths:
    - ""
    services:
    - '*'
status: {}
apiVersion: rbac.istio.io/v1alpha1
kind: ServiceRoleBinding
metadata:
  creationTimestamp: 2019-10-30T17:55:49Z
  generation: 1
  name: productpage-v1-details-v1
  namespace: bookinfo
  ownerReferences:
  - apiVersion: access.smi-spec.io/v1alpha1
    blockOwnerDeletion: true
    controller: true
    kind: TrafficTarget
    name: productpage-v1-details-v1
    uid: 81bef9a7-fb3e-11e9-867e-42010a800172
  resourceVersion: "23951"
  selfLink: /apis/rbac.istio.io/v1alpha1/namespaces/bookinfo/servicerolebindings/productpage-v1-details-v1
  uid: 81e1c733-fb3e-11e9-867e-42010a800172
spec:
  roleRef:
    kind: ServiceRole
    name: productpage-v1-details-v1
  subjects:
  - user: cluster.local/ns/bookinfo/sa/productpage-v1
status: {}

This example deviated slightly from the one linked, because I had trouble getting that one to behave as expected and this was a bit simpler to understand what should be going on.

Status/Future of this Repo

๐Ÿ‘‹ Hi all - I'd like to discuss the future of this repo. The last meaningful library (Go) commit was pre-2020, and the issues requesting istio version support are piling up. I've spent the last few days attempting to convert this project to Go modules (dep ensure hangs and is no longer supported), and the dependency situation is....messy to say the least; several package revisions no longer exist, and I still haven't found a working combination. Obviously, having an SMI adapter for Istio would be fantastic, but I'm curious as to the official status/support of this repository.

When numbers only given in trafficsplit weight returns `0`

For the following TrafficSplit object the VirtualService is never updated because of following error:

apiVersion: split.smi-spec.io/v1alpha1
kind: TrafficSplit
metadata:
  name: reviews-rollout
spec:
  service: reviews
  backends:
  - service: reviews-v1
    weight: 0
  - service: reviews-v2
    weight: 1000

error in operator

{"level":"info","ts":1557923491.9240608,"logger":"controller_trafficsplit","msg":"Reconciling TrafficSplit",
"Request.Namespace":"smi-demo","Request.Name":"reviews-rollout"}
{"level":"info","ts":1557923491.9241369,"logger":"controller_trafficsplit","msg":"------> giving weight:",
"Request.Namespace":"smi-demo","Request.Name":"reviews-rollout","reviews-v1":0}
{"level":"info","ts":1557923491.9241776,"logger":"controller_trafficsplit","msg":"------> giving weight:",
"Request.Namespace":"smi-demo","Request.Name":"reviews-rollout","reviews-v2":0}
{"level":"info","ts":1557923491.9244137,"logger":"controller_trafficsplit","msg":"Updating VirtualService",
"Request.Namespace":"smi-demo","Request.Name":"reviews-rollout","VirtualService.Namespace":"smi-demo","VirtualService.Name":"reviews-rollout-vs"}
{"level":"error","ts":1557923491.9342525,"logger":"kubebuilder.controller","msg":"Reconciler error",
"controller":"trafficsplit-controller","request":"smi-demo/reviews-rollout",
"error":"admission webhook \"pilot.validation.istio.io\" denied the request: configuration is invalid: total destination weight 0 != 100","stacktrace":"github.com/deislabs/smi-adapter-istio/vendor/github.com/go-logr/zapr.(*zapLogger).Error\n\t/home/surajd/go/src/github.com/deislabs/smi-adapter-istio/vendor/github.com/go-logr/zapr/zapr.go:128\ngithub.com/deislabs/smi-adapter-istio/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/home/surajd/go/src/github.com/deislabs/smi-adapter-istio/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:217\ngithub.com/deislabs/smi-adapter-istio/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Start.func1\n\t/home/surajd/go/src/github.com/deislabs/smi-adapter-istio/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:158\ngithub.com/deislabs/smi-adapter-istio/vendor/k8s.io/apimachinery/pkg/util/wait.JitterUntil.func1\n\t/home/surajd/go/src/github.com/deislabs/smi-adapter-istio/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:133\ngithub.com/deislabs/smi-adapter-istio/vendor/k8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/home/surajd/go/src/github.com/deislabs/smi-adapter-istio/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:134\ngithub.com/deislabs/smi-adapter-istio/vendor/k8s.io/apimachinery/pkg/util/wait.Until\n\t/home/surajd/go/src/github.com/deislabs/smi-adapter-istio/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:88"}

This somewhere related to the object code in the function:

func quantityToKilo(q resource.Quantity) int {
	// TODO: reuse existing resource.Quantity methods to get the amount
	numberBytes, suffixBytes := q.CanonicalizeBytes(make([]byte, 18, 18))
	number := strings.Trim(string(numberBytes), "\000")
	suffix := strings.Trim(string(suffixBytes), "\000")
	out, _ := strconv.Atoi(number)
	if suffix == "m" {
		return out
	} else if suffix == "" {
		return out * 1000
	} else {
		return 0
	}
}

But if the TrafficSplit object is changed to following things work just fine.

apiVersion: split.smi-spec.io/v1alpha1
kind: TrafficSplit
metadata:
  name: reviews-rollout
spec:
  service: reviews
  backends:
  - service: reviews-v1
    weight: "0m"
  - service: reviews-v2
    weight: "1000m"

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.