cloudifysource / cloudify-widget Goto Github PK
View Code? Open in Web Editor NEWWidget for embedding a Cloudify "recipe player" in other website, to allow visitors to launch a certain recipe with a single click.
License: Apache License 2.0
Widget for embedding a Cloudify "recipe player" in other website, to allow visitors to launch a certain recipe with a single click.
License: Apache License 2.0
Allow a widget owner to unregister from the system
Require user to login through a social network (start with Twitter, LinkedIn, Facebook and G+) upon launching a widget and record the launching user's details.
Root URL should lead to the login page and not show all the route definition
Credentials include:
Allow a widget owner to:
The create widget dialog should have a help link on how to create recipe and also enable to browse through a list of existing recipies
Add a captcha verification for widget owner registration
Apply a policy to passwords when widget admins register:
When using a CouchBase recipe, located at https://dl.dropbox.com/u/5682483/couchbase181.zip, the widget does not allow it to deploy with the attached error. This recipe seems to be ok.
Currently the widget server starts each VM in the pool serially and waits for it to be fully bootstrapped.
That means that the server takes a lot of time to start.
Need to make this process async and parallel.
on "dev" environment, I started from scratch with a single widget.
I entered wrong input ( wrong recipe details ) and hit "play" in the widget.
The "play" failed with a message "recipe is invalid" which is ok..
I stopped the server and restarted again -
==> saw the following prints
5614 [main] INFO beans.ServerPoolImpl - Started to initialize ServerPool, cold-init=false
7088 [main] INFO beans.ServerPoolImpl - ServerId: 880551 expired or not found in server-pool, address: {private=[Address{addr=10.6.35.171, version=4}, Address{addr=15.185.164.122, version=4}]}
7363 [main] INFO beans.ServerBootstrapperImpl - Server id: 880551 was deleted.
7366 [main] INFO beans.ServerPoolImpl - ServerId: 880549 expired or not found in server-pool, address: {private=[Address{addr=10.6.35.170, version=4}, Address{addr=15.185.164.116, version=4}]}
7604 [main] INFO beans.ServerBootstrapperImpl - Server id: 880549 was deleted.
7611 [main] INFO beans.ServerPoolImpl - Found a busy server, leave it: Server{id=880547, name=cloudify_pool_server1
==> It seems that the pool was changed.
The correct behavior should be - if recipe is invalid, we should return the server to the pool and it was untouched.
When clicking "Play" on any recipe (even recipes that worked before), nothing happens. Log indicates the following issue:
236514176 [play-akka.actor.actions-dispatcher-69] INFO application - Downloading recipe: https://dl.dropbox.com/u/5682483/mongodb.zip to /root/play-2.0.4/cloudify-widget/recipes/1674bab7-09b5-4fe1-b50d-7708320a2833/3999662508835728/mongodb.zip
236515393 [play-akka.actor.actions-dispatcher-69] INFO application - Starting to extract recipe to: /root/play-2.0.4/cloudify-widget/recipes/1674bab7-09b5-4fe1-b50d-7708320a2833/3999662508835728/mongodb.zip
236515393 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: mongodb/mongod-service.groovy
236515394 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: __MACOSX/mongodb/._mongod-service.groovy
236515395 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: mongodb/mongod-service.properties
236515395 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: __MACOSX/mongodb/._mongod-service.properties
236515395 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: mongodb/mongod_install.groovy
236515396 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: __MACOSX/mongodb/._mongod_install.groovy
236515397 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: mongodb/mongod_start.groovy
236515397 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: __MACOSX/mongodb/._mongod_start.groovy
236515398 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: mongodb/mongodb.png
236515398 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: __MACOSX/mongodb/._mongodb.png
236515399 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: mongodb/README.md
236515400 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: __MACOSX/mongodb/._README.md
236515400 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: mongodb/usmlib/mongo-java-driver-2.6.5.jar
236515405 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: __MACOSX/mongodb/usmlib/._mongo-java-driver-2.6.5.jar
236515405 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: __MACOSX/mongodb/._usmlib
236515406 [play-akka.actor.actions-dispatcher-69] INFO application - Extracting: __MACOSX/._mongodb
236515413 [play-akka.actor.actions-dispatcher-69] INFO application - This server 15.185.111.23 was scheduled for destroy after: 3599997 ms
236515415 [play-akka.actor.actions-dispatcher-69] ERROR application -
! @6cjgpf6e6 - Internal server error, for request [POST /widget/start?apiKey=1674bab7-09b5-4fe1-b50d-7708320a2833] ->
play.core.ActionInvoker$$anonfun$receive$1$$anon$1: Execution exception [[IllegalStateException: Timer already cancelled.]]
at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:134) [play_2.9.1.jar:2.0.4]
at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:115) [play_2.9.1.jar:2.0.4]
at akka.actor.Actor$class.apply(Actor.scala:318) [akka-actor.jar:2.0.2]
at play.core.ActionInvoker.apply(Invoker.scala:113) [play_2.9.1.jar:2.0.4]
at akka.actor.ActorCell.invoke(ActorCell.scala:626) [akka-actor.jar:2.0.2]
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:197) [akka-actor.jar:2.0.2]
at akka.dispatch.Mailbox.run(Mailbox.scala:179) [akka-actor.jar:2.0.2]
at akka.dispatch.ForkJoinExecutorConfigurator$MailboxExecutionTask.exec(AbstractDispatcher.scala:516) [akka-actor.jar:2.0.2]
at akka.jsr166y.ForkJoinTask.doExec(ForkJoinTask.java:259) [akka-actor.jar:2.0.2]
at akka.jsr166y.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:975) [akka-actor.jar:2.0.2]
at akka.jsr166y.ForkJoinPool.runWorker(ForkJoinPool.java:1479) [akka-actor.jar:2.0.2]
at akka.jsr166y.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:104) [akka-actor.jar:2.0.2]
Caused by: java.lang.IllegalStateException: Timer already cancelled.
at java.util.Timer.sched(Timer.java:354) ~[na:1.6.0_32]
at java.util.Timer.schedule(Timer.java:170) ~[na:1.6.0_32]
at beans.ExpireServersCollectorImpl.scheduleToDestroy(ExpireServersCollectorImpl.java:47) ~[classes/:na]
at beans.ServerPoolImpl.get(ServerPoolImpl.java:140) ~[classes/:na]
at beans.WidgetServerImpl.deploy(WidgetServerImpl.java:68) ~[classes/:na]
at controllers.Application.start(Application.java:38) ~[classes/:2.0.4]
at Routes$$anonfun$routes$1$$anonfun$apply$1$$anonfun$apply$2.apply(routes_routing.scala:96) ~[classes/:na]
at Routes$$anonfun$routes$1$$anonfun$apply$1$$anonfun$apply$2.apply(routes_routing.scala:96) ~[classes/:na]
at play.core.Router$HandlerInvoker$$anon$5$$anon$1.invocation(Router.scala:1090) ~[play_2.9.1.jar:2.0.4]
at play.core.j.JavaAction$$anon$1.call(JavaAction.scala:33) ~[play_2.9.1.jar:2.0.4]
at play.GlobalSettings$1.call(GlobalSettings.java:57) ~[play_2.9.1.jar:2.0.4]
at play.core.j.JavaAction$class.apply(JavaAction.scala:74) ~[play_2.9.1.jar:2.0.4]
at play.core.Router$HandlerInvoker$$anon$5$$anon$1.apply(Router.scala:1089) ~[play_2.9.1.jar:2.0.4]
at play.core.ActionInvoker$$anonfun$receive$1$$anonfun$6.apply(Invoker.scala:126) ~[play_2.9.1.jar:2.0.4]
at play.core.ActionInvoker$$anonfun$receive$1$$anonfun$6.apply(Invoker.scala:126) ~[play_2.9.1.jar:2.0.4]
at play.utils.Threads$.withContextClassLoader(Threads.scala:17) ~[play_2.9.1.jar:2.0.4]
at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:125) [play_2.9.1.jar:2.0.4]
... 11 common frames omitted
Allow widget owners to login with OAuth2 / facebook / g+ / twitter / stackexchange
Widget VMs should have all ports open, server VMs should be protected and allow only for trivial ports (80 22, 443) to be open
Have a forgot password link to allow for widget owners to reset their password once forgotten
If, for some odd reason, the cookies "instanceId" and "publicIp" are not deleted on "widget stop" action, you can not run another instance of this widget ever.
to reproduce:
==> Infinite loop. The cookies must be deleted manually.
There are many ways to fix this issue, I think we should implement all.
First of all - lets encode the cookie name. We are using the URL as the cookie name.
I think we should:
Other than that - we can modify the flow a bit to enable recovery:
Allow widget owners to edit to details (Recipe URL, title, etc.) of a widget after it's been saved.
Error message from log file:
229691211 [Thread-289] INFO application - Starting to create new Server [imageId=1358, flavorId=102]
229691331 [Thread-289] ERROR application - Failed to bootstrap machine.
org.jclouds.rest.AuthorizationException: POST https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/38441950719398/servers HTTP/1.1 -> HTTP/1.1 401 Unauthorized
at org.jclouds.openstack.nova.v2_0.handlers.NovaErrorHandler.handleError(NovaErrorHandler.java:63) ~[openstack-nova-1.5.1.jar:1.5.1]
at org.jclouds.http.handlers.DelegatingErrorHandler.handleError(DelegatingErrorHandler.java:69) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.http.internal.BaseHttpCommandExecutorService$HttpResponseCallable.shouldContinue(BaseHttpCommandExecutorService.java:197) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.http.internal.BaseHttpCommandExecutorService$HttpResponseCallable.call(BaseHttpCommandExecutorService.java:167) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.http.internal.BaseHttpCommandExecutorService$HttpResponseCallable.call(BaseHttpCommandExecutorService.java:135) ~[jclouds-core-1.5.1.jar:1.5.1]
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) ~[na:1.6.0_32]
at java.util.concurrent.FutureTask.run(FutureTask.java:138) ~[na:1.6.0_32]
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) ~[na:1.6.0_32]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) ~[na:1.6.0_32]
at java.lang.Thread.run(Thread.java:662) [na:1.6.0_32]
at org.jclouds.concurrent.config.DescribingExecutorService.submit(DescribingExecutorService.java:89) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.http.internal.BaseHttpCommandExecutorService.submit(BaseHttpCommandExecutorService.java:132) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.http.TransformingHttpCommandExecutorServiceImpl.submit(TransformingHttpCommandExecutorServiceImpl.java:54) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.http.TransformingHttpCommandImpl.execute(TransformingHttpCommandImpl.java:73) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.rest.internal.AsyncRestClientProxy.createListenableFutureForHttpRequestMappedToMethodAndArgs(AsyncRestClientProxy.java:248) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.rest.internal.AsyncRestClientProxy.invoke(AsyncRestClientProxy.java:148) ~[jclouds-core-1.5.1.jar:1.5.1]
at $Proxy91.create(Unknown Source) ~[na:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_32]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_32]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_32]
at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_32]
at org.jclouds.concurrent.internal.SyncProxy.invoke(SyncProxy.java:164) ~[jclouds-core-1.5.1.jar:1.5.1]
at $Proxy92.create(Unknown Source) ~[na:na]
at beans.ServerBootstrapperImpl.createServerNode(ServerBootstrapperImpl.java:132) ~[classes/:na]
at beans.ServerBootstrapperImpl.createServers(ServerBootstrapperImpl.java:88) ~[classes/:na]
at beans.ServerPoolImpl$1.run(ServerPoolImpl.java:173) [classes/:na]
at java.lang.Thread.run(Thread.java:662) [na:1.6.0_32]
at org.jclouds.concurrent.config.DescribingExecutorService.submit(DescribingExecutorService.java:89) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.http.internal.BaseHttpCommandExecutorService.submit(BaseHttpCommandExecutorService.java:132) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.http.TransformingHttpCommandExecutorServiceImpl.submit(TransformingHttpCommandExecutorServiceImpl.java:54) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.http.TransformingHttpCommandImpl.execute(TransformingHttpCommandImpl.java:73) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.rest.internal.AsyncRestClientProxy.createListenableFutureForHttpRequestMappedToMethodAndArgs(AsyncRestClientProxy.java:248) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.rest.internal.AsyncRestClientProxy.invoke(AsyncRestClientProxy.java:148) ~[jclouds-core-1.5.1.jar:1.5.1]
at $Proxy91.create(Unknown Source) ~[na:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_32]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_32]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_32]
at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_32]
at org.jclouds.concurrent.internal.SyncProxy.invoke(SyncProxy.java:164) ~[jclouds-core-1.5.1.jar:1.5.1]
at $Proxy92.create(Unknown Source) ~[na:na]
at beans.ServerBootstrapperImpl.createServerNode(ServerBootstrapperImpl.java:132) ~[classes/:na]
at beans.ServerBootstrapperImpl.createServers(ServerBootstrapperImpl.java:88) ~[classes/:na]
at beans.ServerPoolImpl$1.run(ServerPoolImpl.java:173) [classes/:na]
at java.lang.Thread.run(Thread.java:662) [na:1.6.0_32]
Caused by: org.jclouds.http.HttpResponseException: request: POST https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/38441950719398/servers HTTP/1.1 [{"server":{"name":"cloudify_pool_server1355644992048","imageRef":"1358","flavorRef":"102","key_name":"cloudify","security_groups":[{"name":"default"}]}}] failed with response: HTTP/1.1 401 Unauthorized
at org.jclouds.openstack.nova.v2_0.handlers.NovaErrorHandler.handleError(NovaErrorHandler.java:48) ~[openstack-nova-1.5.1.jar:1.5.1]
at org.jclouds.http.handlers.DelegatingErrorHandler.handleError(DelegatingErrorHandler.java:69) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.http.internal.BaseHttpCommandExecutorService$HttpResponseCallable.shouldContinue(BaseHttpCommandExecutorService.java:197) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.http.internal.BaseHttpCommandExecutorService$HttpResponseCallable.call(BaseHttpCommandExecutorService.java:167) ~[jclouds-core-1.5.1.jar:1.5.1]
at org.jclouds.http.internal.BaseHttpCommandExecutorService$HttpResponseCallable.call(BaseHttpCommandExecutorService.java:135) ~[jclouds-core-1.5.1.jar:1.5.1]
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) ~[na:1.6.0_32]
at java.util.concurrent.FutureTask.run(FutureTask.java:138) ~[na:1.6.0_32]
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) ~[na:1.6.0_32]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) ~[na:1.6.0_32]
... 1 common frames omitted
229691332 [Thread-289] ERROR application - ServerPool failed to create a new server node
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.RangeCheck(ArrayList.java:547) ~[na:1.6.0_32]
at java.util.ArrayList.get(ArrayList.java:322) ~[na:1.6.0_32]
at beans.ServerPoolImpl$1.run(ServerPoolImpl.java:174) ~[classes/:na]
at java.lang.Thread.run(Thread.java:662) [na:1.6.0_32]
229691339 [play-akka.actor.actions-dispatcher-55] ERROR application -
! @6cjgpf6dp - Internal server error, for request [POST /widget/607251/stop?apiKey=238c5cbd-ec8d-4056-b66a-474bd04f77f4] ->
play.core.ActionInvoker$$anonfun$receive$1$$anon$1: Execution exception [[AuthorizationException:
<title>401 Unauthorized</title>This is a serious security breach. Show stopper.
Have a graphical progress indication (e.g. by grdually filling up the circle surrounding the play/stop button)
Have 3 states for the play and stop buttons: normal, hovered on and clicked (only when the mouse is down)
Support HTTPS for widgets owner dashboard
Upgrade cloudify installation that the widget uses to 2.3
The admin dashboard lists all widgets in a flat table. The row should be grouped by the widget owner user id
When filling in the cloud credentials before clicking "Play", the widget server bootstraps a new cloudify manager for the user.
This should happen only once per user.
This means the following:
When a widget owner registers he/she should receive an activation email with an activation link. Only once the activation link is clicked should the newly created account be enabled.
Supprt recipes that require sudo with VMs created by the widget server.
Should be done by disabling requiretty for VMs created by widget server.
This bug has 2 origins:
Application.stop - simply stops the instance with no verification. You can easily write a script that tries all instance IDs (it is numeric ) and you will probably hit one.
This method is not protected by security so everyone can do it. we should at least verify against the apiKey which is available in the controller but simply not used.
WidgetAdmin.shutdownInstance does not verify the user's ownership on the widget. We can verify it by looking at "WidgetInstance" - we simply don't do it..
The API to "widgetServer" bean should use the "WidgetInstance" model.
The "WidgetInstance" model should expose "findBy" method with user and instanceId.
This way we keep more or less the same interface only secured, and we enforce this on every developer in the future.
The twitter, facebook and Plus button should auto fill the content of the shared post with meaningful input (e.g. Launch on the cloud in a single click using the Cloudify widget )
In the widget owner and admin screens, add a column that lists the number of currently running instances, not just total number of launches
Try to embed 2 widgets in the same page
==> One overtakes the other.
Reproduce:
==> Nothing happen. State is still disabled.
Allow to customize the following elements as part of the widget creation:
A script that, given a host, can install the server:
Support regular Cloudify deployment and not just localcloud for widget launch
When launching a cloudify app with user specific user-name/password the links to the console and app should point to the user cloudify manager and not the local cloud machine
Add Delete widget functionality in the widget dashboard
Allow widget owner to specify one of 3 predefined sizes for the widget when embedding it: small, medium (default, indentical to current size) and large
The actions menu for each widget in the dashboard have an option to view the widget by creating a plain page with the widget embedded in it. Very useful for previewing the widget.
To support inheritance, the user needs to zip all the related recipes (extending and extended) in one zip, and specify to cloudify which directory or service is the right one to point to when installing
Need to add $JAVA_HOME/bin to $PATH when bootstrapping the machine
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.