1 | _ = require 'underscore'
|
2 | fs = require "fs-extra"
|
3 | os = require "os"
|
4 | url = require "url"
|
5 | path = require "path"
|
6 | http = require "http"
|
7 | https = require "https"
|
8 | shell = require "shelljs"
|
9 | helpers = require '../modules/common/helpers'
|
10 | request = require "request"
|
11 | querystring = require "querystring"
|
12 | readDirFiles = require 'read-dir-files'
|
13 | Processes = require '../lib/processes'
|
14 | KDKite = require '../lib/kdkite'
|
15 | Controller = require '../lib/controller'
|
16 |
|
17 | if process.env['HOME']
|
18 | homedir = path.join process.env['HOME'], '.kd'
|
19 | else
|
20 | homedir = '/root/.kd'
|
21 |
|
22 | kitemanifest = require "#{homedir}/kd-manifest.json"
|
23 | kitehelper = require "kite-amqp/lib/kite-amqp/kite.coffee"
|
24 |
|
25 | {ask, logger} = require "../lib/utils"
|
26 | {manifest, kite} = require "../lib/common"
|
27 | {exec, spawn} = require "child_process"
|
28 | {guard, findFile} = require '../modules/common/helpers'
|
29 |
|
30 | module.exports = class KiteController extends Controller
|
31 |
|
32 | help_txt:"""
|
33 | Kites are awesome simple processes that can do amazing things. (go check http://kd.io/kites)
|
34 | """
|
35 |
|
36 | @set
|
37 | commands:
|
38 | 'create': ['create', 'Creates a kite']
|
39 | 'run': ['run', 'Runs the kite and all its dependencies']
|
40 | 'install': ['install', """
|
41 | Installs kites dependencies
|
42 |
|
43 | usage:
|
44 |
|
45 | kd kite install
|
46 |
|
47 | """]
|
48 |
|
49 | 'listdependencies': ['listDependencies',
|
50 | '''
|
51 | kd listdependencies
|
52 | '''
|
53 | ]
|
54 |
|
55 | 'removedependency': ['removeDependency',
|
56 | '''
|
57 | Removes kite dependency:
|
58 |
|
59 | usage:
|
60 | kd removedependency /projects/mykite
|
61 | '''
|
62 | ]
|
63 |
|
64 | 'zip': ['createZip', 'creates a zip file from kite']
|
65 |
|
66 | 'deploy': ['createZip', 'deploys the kite file']
|
67 |
|
68 | 'list': ['list', 'Lists running kites']
|
69 |
|
70 | 'cluster': ['cluster', 'Kite cluster related commands']
|
71 |
|
72 | 'adddependency': ['addDependency',
|
73 | '''Adds a service dependency
|
74 |
|
75 | That means when you run this kite, it will run the other kites that this kite depends on.
|
76 |
|
77 | You can add another kite as a runtime dependency from a git repo, a zip url or from local filesystem.
|
78 |
|
79 | usage:
|
80 | kd adddependency git://
|
81 |
|
82 | kd adddependency /projects/mykite/
|
83 |
|
84 | kd adddependency http://example.com/mykite.zip
|
85 |
|
86 | ''']
|
87 |
|
88 | constructor: (@configuration)->
|
89 | {@config} = @configuration
|
90 | @config.KODING_ROOT or= "https://koding.com"
|
91 | @cwd = process.cwd()
|
92 |
|
93 | create: (type, name, kitePath=@cwd)->
|
94 | console.log "type", type
|
95 | guard (type not in ["worker", "server", "server-express"]), "You have to define a type for your kite: 'worker' or 'server'"
|
96 | guard not name, "Please define a name for your kite."
|
97 | guard name.match(/[^\w]/), "Please do not use special chars in kite name."
|
98 |
|
99 | kiteDir = path.join kitePath, "#{name}.kite"
|
100 | console.log "Creating #{name} kite in #{kiteDir}"
|
101 |
|
102 | kite = new KDKite(kiteDir)
|
103 | kite.name = name
|
104 | kite.username = @config.username
|
105 | kite.mail = @config.mail
|
106 | kite.version = '1.0.1'
|
107 | kite.cloneFrom "#{type}.kite", ->
|
108 | kite.prepare (err)->
|
109 | process.stdout.write os.EOL
|
110 | console.log """
|
111 |
|
112 | Kite created as #{type} successfully.
|
113 | To run, do:
|
114 |
|
115 | cd #{path.relative process.cwd(), kiteDir}
|
116 | kd kite run
|
117 | """
|
118 | return kite
|
119 |
|
120 | getKiteFromPath: (dir=@cwd)->
|
121 | kite = new KDKite(dir)
|
122 | kite.processes = @processes
|
123 | return kite
|
124 |
|
125 | applicationInstalled:(application)->
|
126 | exec "which java", (error, stdout, stderr)->
|
127 | if error
|
128 | return false
|
129 | return true
|
130 |
|
131 | runMergen:(callback)->
|
132 | mergen = spawn('mergen')
|
133 | mergen.stdout.on 'data', (d)->
|
134 | console.log ">>>>", d.toString()
|
135 | search = "Mergen Server listening for commands on"
|
136 | if d.toString().indexOf(search) > -1
|
137 | callback /([0-9]+)/.exec(d.toString())[1]
|
138 | mergen.stderr.on 'data', (d)->
|
139 | console.log "" + d
|
140 |
|
141 | prerun:(callback)->
|
142 | if not @applicationInstalled("java")
|
143 | console.warn "java is not installed, you wont be able to communicate with other kites, or use datastore"
|
144 | console.warn "please install java by visiting http://java.com/download"
|
145 | else
|
146 |
|
147 | @runMergen (port)->
|
148 | console.log "here comes our port", port
|
149 | return callback(port)
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 | cluster:(cmd)->
|
166 | if cmd is "create"
|
167 | console.log __dirname
|
168 | process.chdir path.join(__dirname, 'resources')
|
169 | vagrant = spawn('vagrant', ['up'])
|
170 | vagrant.stdout.on 'data', (d)-> console.log "" + d
|
171 | vagrant.stderr.on 'data', (d)-> console.log "" + d
|
172 |
|
173 | run:(dir=@cwd)->
|
174 | console.log "preparing...."
|
175 | process.chdir dir
|
176 | @prerun (port)=>
|
177 | console.log "here is our port", port
|
178 | @run_(dir, port)
|
179 |
|
180 | run_:(dir=@cwd, port=6380)->
|
181 |
|
182 | @processes = new Processes()
|
183 | kite = @getKiteFromPath(dir)
|
184 | kite.prepare ->
|
185 | console.log "prepare completed !!!!"
|
186 | kite.run(messageBusPort:port)
|
187 |
|
188 | net = require 'net'
|
189 | server = net.createServer (socket) =>
|
190 | cmds =
|
191 | 'hosts': (args, cb)=>
|
192 | @mergenData.hkeys "kd-runner", (err, hosts)->
|
193 | console.log hosts
|
194 | cb hosts.join("\n")
|
195 |
|
196 | 'list': (args, cb)=>
|
197 | ret = []
|
198 | for i of @processes.list
|
199 | ret.push "#{@processes.list[i].pid}\t#{i}\t#{ (Date.now() - @processes.list[i].startedAt)/1000 } seconds"
|
200 | cb ret.join("\n")
|
201 |
|
202 | 'status': (name, cb)=>
|
203 | if not @processes.list[name]
|
204 | return 'no such process'
|
205 | p = @processes.list[name]
|
206 | cb "running for #{(Date.now() - p.startedAt) / 1000 } seconds \t with pid #{p.pid}"
|
207 |
|
208 | 'attach': (directory, cb)=>
|
209 | kite = new KDKite(directory[0])
|
210 | kite.processes = @processes
|
211 | kite.prepare ->
|
212 | console.log "prepared kite at ", directory
|
213 | kite.run()
|
214 | cb "attached"
|
215 |
|
216 | 'kill': (name, cb)->
|
217 | cb 'TODO'
|
218 |
|
219 | 'restart': (name, cb)->
|
220 | cb 'TODO'
|
221 |
|
222 | 'socketwrite': (args, cb)=>
|
223 | console.log("socket write called", args)
|
224 | socket.write args.join(' ') + "\n"
|
225 | cb("") if cb
|
226 |
|
227 | socket.on 'data', (data) ->
|
228 | cmdline = data.toString().split("\n")
|
229 | cmdline = cmdline[0].replace(/\r$/, '')
|
230 | k = cmdline.split(' ')
|
231 | try
|
232 | cmds[k[0]] k[1...], (ret)->
|
233 | socket.write ret + "\n"
|
234 | catch Error
|
235 | console.trace Error
|
236 | ret = Error.toString()
|
237 | socket.write ret + "\n"
|
238 |
|
239 |
|
240 |
|
241 | listDependencies: ()->
|
242 | kite = @getKiteFromPath(@cwd)
|
243 | kite.listDependencies()
|
244 |
|
245 | removeDependency: (dep)->
|
246 | kite = @getKiteFromPath(@cwd)
|
247 | kite.removeDependency dep, ->
|
248 |
|
249 | console.log "Dependency removed"
|
250 |
|
251 | addDependency: (dep)->
|
252 | kite = @getKiteFromPath(@cwd)
|
253 | kite.addDependency dep, ->
|
254 | console.log "Dependency added"
|
255 |
|
256 | createZip:()=>
|
257 | sha1file = (file)->
|
258 | crypto = require('crypto')
|
259 | shasum = crypto.createHash('sha1')
|
260 | s = fs.readFileSync(file)
|
261 | return shasum.update(s).digest("hex")
|
262 |
|
263 | kite = @getKiteFromPath(@cwd)
|
264 | kite.prepare =>
|
265 | console.log "Creating zip file"
|
266 | zipfilename = "/tmp/#{kite.name}.zip"
|
267 |
|
268 | process.chdir ".."
|
269 | zip = spawn('zip', ['-r', zipfilename, "#{kite.name}.kite", '-x', '*/node_modules/*'])
|
270 | zip.stdout.on 'data', (d)-> console.log "" + d
|
271 | zip.stderr.on 'data', (d)-> console.log "" + d
|
272 |
|
273 | zip.on 'exit', (code)=>
|
274 | if code isnt 0
|
275 | console.log('zip process exited with code ' + code);
|
276 | else
|
277 | console.log "done zip, now uploading"
|
278 |
|
279 | client = require('needle')
|
280 |
|
281 | url = "#{@config.KODING_ROOT}/-/kd/upload"
|
282 |
|
283 | filekey = path.basename(zipfilename)
|
284 | data =
|
285 | username: @config.username
|
286 | key: @config.publicKey
|
287 | hash: sha1file(zipfilename)
|
288 |
|
289 | data[filekey] = { file: zipfilename, content_type: 'application/zip' }
|
290 | data["#{filekey}-size"] = fs.statSync(zipfilename).size
|
291 |
|
292 | console.log "uploading to ", url
|
293 | client.post url, data, multipart:true, (err, resp, body)->
|
294 | console.log(err)
|
295 | console.log("Got status code " + resp.statusCode)
|
296 | console.log(body)
|
297 | options = JSON.parse body
|
298 | fs.unlink(zipfilename)
|
299 | console.log "options", options
|
300 |
|
301 | mykite = kitehelper.worker kitemanifest,
|
302 | list: ()->
|
303 | options['kiteName'] = "#{kite.name}.kite"
|
304 | @group "Deployer", "deploy", [options], (err, opts)->
|
305 | console.log "here", err, opts.args[0].id
|
306 | console.log "Deployed to", opts.args[0].id
|
307 |
|
308 | process.exit 0
|
309 | , true
|
310 |
|
311 | mykite.start ()->
|
312 | mykite.callFunction 'list', [], ()->
|
313 | console.log "done"
|
314 |
|
315 | install: ()->
|
316 | kite = @getKiteFromPath(@cwd)
|
317 | kite.prepare ->
|
318 | console.log "Installation complete"
|
319 |
|
320 | list: ()->
|
321 | kites = []
|
322 | listsent = false
|
323 | setTimeout ()->
|
324 | for i in kites
|
325 | console.log ">>>>", i
|
326 | process.exit 0
|
327 | , 3000
|
328 |
|
329 | mykite = kitehelper.worker kitemanifest,
|
330 | list: ()->
|
331 | @everyone "kite.who", [], (err, reply)->
|
332 | kites.push reply.args[1]
|
333 |
|
334 | mykite.start ()->
|
335 | mykite.callFunction 'list', [], ()->
|
336 | console.log "done"
|