Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #300 Kubernetes config added for autodeployment #381

Merged
merged 1 commit into from
Aug 21, 2017

Conversation

imujjwal96
Copy link
Contributor

Description

Following are the configurations added with credentials for my local repositories. Changes would be required with original yaydoc credentials.
The added configurations are inspired from fossasia/open-event-webapp and fossasia/open-event-orga-server

Related Issue

issue #300

Motivation and Context

In order to make Yaydoc into a stable service we need to set up the infrastructure. The master branch of Yaydoc is currently deployed at Heroku (https://yaydoc.herokuapp.com). However, we cannot rely much on a free tier Heroku app to host Yaydoc due to various limitations. Hence, there is a need to deploy Yaydoc to FOSSASIA's Google Cloud.

How Has This Been Tested?

Deployed at http://yaydoc.tk

Screenshots (if appropriate):

Types of changes

  • Bug fix
  • New feature

Checklist:

  • I have read the Contribution & Best practices Guide and my PR follows them.
  • There is a corresponding issue for this pull request.
  • Mentioned the Issue number in the pull request commit message Fixes #<number> commit message
  • There is only one commit per issue.

@imujjwal96 imujjwal96 requested review from poonai and pri22296 August 13, 2017 10:34
@ghost ghost added the needs-review label Aug 13, 2017
@ghost ghost assigned imujjwal96 Aug 13, 2017
@poonai
Copy link
Contributor

poonai commented Aug 14, 2017

@imujjwal96 could you update the PR with your jvm change ?so that I can see where I can help

@imujjwal96 imujjwal96 force-pushed the kubernetes branch 2 times, most recently from dda5671 to ba50f30 Compare August 14, 2017 14:48
@imujjwal96
Copy link
Contributor Author

@Sch00lb0y Updated

@poonai
Copy link
Contributor

poonai commented Aug 14, 2017

  • I think java environment variable is not set properly
  • try with open JDK
    The best solution I can think is that instead of building the image from node, build the image from ubuntu then install node and Java.
    @imujjwal96 I hope this points will help you 😄

@@ -1,8 +1,9 @@
language: python

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need docker service too

Dockerfile Outdated
@@ -2,7 +2,8 @@ FROM node:boron

# Update and install packages
RUN apt-get update && \
apt-get install -y python python-dev python-pip python-virtualenv zip rsync && rm -rf /var/lib/apt/lists/*
apt-get install -y python python-dev python-pip python-virtualenv zip rsync default-jdk && \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JDK will get installed correctly here. All you need to do is set the JAVA_HOME env var properly and add $JAVA_HOME/bin to your PATH

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making this change:

ENV JAVA_HOME /usr/lib/jvm/default-jdk/
RUN export JAVA_HOME
RUN export PATH="$JAVA_HOME/bin:$PATH"

i'm getting these errors

/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/aaa/PublicKeyRegistrationService.java:201: error: illegal start of expression
if (!IntStream.of(allowedKeySizesRSA).anyMatch(x -> x == finalKeyLength)) {
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/aaa/PublicKeyRegistrationService.java:304: error: illegal start of expression
if (!IntStream.of(allowedKeySizesRSA).anyMatch(x -> x == keySize)) {
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/aaa/GetAllUsers.java:69: error: illegal start of expression
authorized.forEach(client -> keysList.add(client.toString()));
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/aaa/UserManagementService.java:87: error: illegal start of expression
authorized.forEach(client -> users.put(client.getClient(), client.toJSON()));
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/aaa/SignUpService.java:210: error: illegal start of expression
authorized.forEach(client -> keysList.add(client.toString()));
^
Loading source files for package ai.susi.server.api.learning...
Loading source files for package ai.susi.server.api.vis...
Loading source files for package ai.susi.server.api.service...
Loading source files for package ai.susi.server.api.cms...
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/cms/ModelListService.java:39: error: ')' expected
String[] models = DAO.model_watch_dir.list((current, name) -> new File(current, name).isDirectory());
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/cms/ModelListService.java:39: error: illegal start of expression
String[] models = DAO.model_watch_dir.list((current, name) -> new File(current, name).isDirectory());
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/cms/ModelListService.java:39: error: ';' expected
String[] models = DAO.model_watch_dir.list((current, name) -> new File(current, name).isDirectory());
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/cms/LanguageListService.java:55: error: ')' expected
String[] languages = group.list((current, name) -> new File(current, name).isDirectory());
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/cms/LanguageListService.java:55: error: illegal start of expression
String[] languages = group.list((current, name) -> new File(current, name).isDirectory());
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/cms/LanguageListService.java:55: error: ';' expected
String[] languages = group.list((current, name) -> new File(current, name).isDirectory());
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/cms/GetAllLanguages.java:65: error: ')' expected
String[] languages = group.list((current, name) -> new File(current, name).isDirectory());
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/cms/GetAllLanguages.java:65: error: illegal start of expression
String[] languages = group.list((current, name) -> new File(current, name).isDirectory());
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/cms/GetAllLanguages.java:65: error: ';' expected
String[] languages = group.list((current, name) -> new File(current, name).isDirectory());
^
Loading source files for package ai.susi.server.api.susi...
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:53: error: illegal start of expression
tokenstats.forEach(tml -> {
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:53: error: illegal start of expression
tokenstats.forEach(tml -> {
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:53: error: ';' expected
tokenstats.forEach(tml -> {
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:54: error: illegal start of expression
LinkedHashMap<String, Integer> m = tml.getMap();
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:54: error: illegal start of expression
LinkedHashMap<String, Integer> m = tml.getMap();
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:54: error: ';' expected
LinkedHashMap<String, Integer> m = tml.getMap();
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:60: error: ')' expected
m.forEach((k,v) -> {
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:60: error: illegal start of expression
m.forEach((k,v) -> {
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:60: error: illegal start of expression
m.forEach((k,v) -> {
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:65: error: illegal start of type
});
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:66: error: <identifier> expected
buffer.append("\n");
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:66: error: illegal start of type
buffer.append("\n");
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:68: error: class, interface, or enum expected
});
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:80: error: class, interface, or enum expected
FileHandler.setCaching(response, 60);
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:81: error: class, interface, or enum expected
post.setResponse(response, "text/plain");
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:82: error: class, interface, or enum expected
response.getOutputStream().write(UTF8.getBytes(buffer.toString()));
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:83: error: class, interface, or enum expected
post.finalize();
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/UnansweredServlet.java:84: error: class, interface, or enum expected
}
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:77: error: ')' expected
dbAccess.put(Pattern.compile("SELECT +?(.*?) +?FROM +?" + serviceName + " +?WHERE +?query ??= ??'(.*?)' ??;"), (flow, matcher) -> {
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:77: error: illegal start of expression
dbAccess.put(Pattern.compile("SELECT +?(.*?) +?FROM +?" + serviceName + " +?WHERE +?query ??= ??'(.*?)' ??;"), (flow, matcher) -> {
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:77: error: illegal start of expression
dbAccess.put(Pattern.compile("SELECT +?(.*?) +?FROM +?" + serviceName + " +?WHERE +?query ??= ??'(.*?)' ??;"), (flow, matcher) -> {
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:94: error: illegal start of type
});
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:97: error: class, interface, or enum expected
public static byte[] loadData(String serviceURL, String testquery) throws IOException {
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:99: error: class, interface, or enum expected
int qp = serviceURL.indexOf("$query$");
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:100: error: class, interface, or enum expected
String url = qp < 0 ? serviceURL + encodedQuery : serviceURL.substring(0, qp) + encodedQuery + serviceURL.substring(qp + 7);
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:101: error: class, interface, or enum expected
return loadData(url);
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:102: error: class, interface, or enum expected
}
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:104: error: class, interface, or enum expected
public static byte[] loadData(String url) throws IOException {
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:108: error: class, interface, or enum expected
ByteArrayOutputStream baos = new ByteArrayOutputStream();
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:109: error: class, interface, or enum expected
int n;
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:110: error: class, interface, or enum expected
byte[] buffer = new byte[16384];
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:111: error: class, interface, or enum expected
try {while ((n = cc.inputStream.read(buffer, 0, buffer.length)) != -1) baos.write(buffer, 0, n);} catch (IOException e) {}
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:111: error: class, interface, or enum expected
try {while ((n = cc.inputStream.read(buffer, 0, buffer.length)) != -1) baos.write(buffer, 0, n);} catch (IOException e) {}
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:113: error: class, interface, or enum expected
byte[] b = baos.toByteArray();
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:116: error: class, interface, or enum expected
cc.close();
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:120: error: class, interface, or enum expected
int i = b.length;
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:121: error: class, interface, or enum expected
while (i-- > 0) if (b[i] > 32) break;
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:122: error: class, interface, or enum expected
if (i > 2) {
^
/usr/src/app/temp/[email protected]/18665bd1-c0a7-446c-9a1b-6cd4649d50a5/src/ai/susi/server/api/susi/ConsoleService.java:126: error: class, interface, or enum expected

Copy link
Member

@niranjan94 niranjan94 Aug 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RUN export JAVA_HOME is not needed.

Instead of RUN export PATH="$JAVA_HOME/bin:$PATH" do,

ENV PATH $JAVA_HOME/bin:$PATH

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imujjwal96 I think these are java doc warning. please ensure that javadoc is creating are not

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And from from the looks of your log, I have a slight feeling there maybe some java version incompatibility. Instead of doing an apt-get install default-jdk, install the actual required jdk version.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@niranjan94 thanks a lot.
I am not aware of the jdk version. I think Dockerfile installs 1.7 which is not working

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The default-jdk for jessie is open-jdk7 .. So first step is to installl the correct version

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I defined this version default-jdk=2:1.8-56ubuntu2
And got version not found as response

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What version is required ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@niranjan94 we using this build pack https://github.com/heroku/heroku-buildpack-jvm-common/blob/master/bin/java in HEROKU. it has mentioned as 1.8. I think this will help.

@imujjwal96 imujjwal96 force-pushed the kubernetes branch 2 times, most recently from c3a20fd to ccdc956 Compare August 16, 2017 17:18
@imujjwal96
Copy link
Contributor Author

@niranjan94 I made some changes and it is working now. Please check if they are efficient. Thanks a lot for the guidance.

@ghost
Copy link

ghost commented Aug 16, 2017

Hi @imujjwal96!

Looks like your PR has some conflicts. 😟
Could you resolve them and rebase on top of the latest upstream code ?

@imujjwal96 imujjwal96 force-pushed the kubernetes branch 2 times, most recently from c761f7a to 316e574 Compare August 17, 2017 10:27
@imujjwal96
Copy link
Contributor Author

@niranjan94 Is the PR fine now? What about the domain name and gcloud json credentials?
https://github.com/fossasia/yaydoc/pull/381/files#diff-fb6f9280c51afe08367bd75efa2ef846R24

@imujjwal96 imujjwal96 force-pushed the kubernetes branch 2 times, most recently from 11ddae0 to 6131a1a Compare August 18, 2017 10:24
@niranjan94
Copy link
Member

niranjan94 commented Aug 18, 2017

@imujjwal96 PR looks fine. Domain name and google cloud creds, @mariobehling should be able to help.

@imujjwal96
Copy link
Contributor Author

@niranjan94 @pri22296 @Sch00lb0y I've updated this adding mongodb deployment/service.
Please review. http://yaydoc.org

@poonai
Copy link
Contributor

poonai commented Aug 19, 2017

@imujjwal96 I have a doubt. Will mongo data remain on the server on each deployment? please clarify my doubt

@imujjwal96
Copy link
Contributor Author

I have no idea! @niranjan94

Will mongo data remain on the server on each deployment?

@poonai
Copy link
Contributor

poonai commented Aug 19, 2017

I think it'll be erased. please confirm by redeploying manually.

@imujjwal96
Copy link
Contributor Author

imujjwal96 commented Aug 19, 2017

@Sch00lb0y We won't be performing any redeployment per se.

docker push ujjwalbhardwaj/yaydoc
kubectl set image deployment/yaydoc --namespace=web yaydoc=ujjwalbhardwaj/yaydoc:$TRAVIS_COMMIT

These are the commands that will execute on each commit on yaydoc

@niranjan94
Copy link
Member

@imujjwal96 you need to attach a persistent data store to the mongo instance. Its missing.

@niranjan94
Copy link
Member

A restart of the mongo pod (kuberentes would do that in case it notices some error in the pod) would result in loss of all data.

@imujjwal96
Copy link
Contributor Author

@niranjan94 I updated mongo-deployment.yml as

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
   name: mongo
   namespace: mongo
spec:
  template:
    metadata:
      labels:
        run: mongo
    spec:
      containers:
      - name: mongo
        image: mongo
        ports:
        - containerPort: 27017
        volumeMounts:
        - name: mongo-persistent-storage
          mountPath: /data/db
      volumes:
      - name: mongo-persistent-storage
        gcePersistentDisk:
          pdName: mongo-disk
          fsType: ext4

and ran gcloud compute disks create --size=50GB --zone=us-west1-a mongo-disk
But now mongodb doesn't seem to be working. Also, the container doesn't show any error.

@imujjwal96
Copy link
Contributor Author

@niranjan94 i faced this problem once before when i had set mongodb://mongo:27017/yaydoc as the mongodb URI. Eventually had to change it to mongodb://mongo.mongo:27017/yaydoc.
Can something similar be the cause?

@imujjwal96
Copy link
Contributor Author

Apparently it was an error in the Dockerhub repository. Rebuilding and pushing it solved the problem.

@poonai
Copy link
Contributor

poonai commented Aug 20, 2017

@imujjwal96 now the deployment working with persistent storage?

@imujjwal96
Copy link
Contributor Author

imujjwal96 commented Aug 20, 2017

yes it is! Tried and tested

@imujjwal96
Copy link
Contributor Author

@niranjan94 @pri22296 @Sch00lb0y Anything else?

Copy link
Contributor

@poonai poonai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks Fine

@ghost ghost removed the needs-review label Aug 20, 2017
spec:
containers:
- name: yaydoc
image: ujjwalbhardwaj/yaydoc:latest
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this use fossasia's yaydoc image?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've asked you to manually deploy yaydoc to dockerhub, haven't I?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, and I told you that I was getting an error while doing. I tried a lot of things but couldn't find any solution.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! I must have missed that!
Let it use my image until one is deployed in FOSSASIA.

@mariobehling mariobehling merged commit 3d0a882 into fossasia:master Aug 21, 2017
@ghost ghost added the ready-to-ship label Aug 21, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants