Property refresh without Bounce/Deploy/Redeploy

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Property refresh without Bounce/Deploy/Redeploy

mrai
Hi Yan,

We are Using GLU for Deployments Automation, We have a requirement came up to just updates the App properties without Bounce, Redeploy or Deploy. We will be able to update the properties alone when the app is in running/stopped state and doesn’t want App to Bounce/Redeploy  or any other activity to be happened.

How can we achieve this, Do we create a new state machine or can be achived using Plan Plugin?

Thanks in advance,
Munmun
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Property refresh without Bounce/Deploy/Redeploy

frenchyan
Administrator
Can you explain what you call App and properties exactly? And what is your use case?

Glu does not really have these concept built-in: you write a glu script which has a set of methods (start, stop, etc...) backed by a state machine. What the glu script does in each phase is up to you. "Bounce" is a shortcut that calls "stop" followed by "start". Of course in general those actions map to forking/starting external processes.

Yan
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Property refresh without Bounce/Deploy/Redeploy

mrai
Hi Yan,

properties here refers to the environment variables or configurations (key-value pairs) which are set before executing the application. Our requirement is to do a hot deployment when the properties are updated.

From what I understand, we need to write our own state machine for this. Please correct me if wrong or if we can reuse any existing state machine.

Thanks,
Munmun
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Property refresh without Bounce/Deploy/Redeploy

frenchyan
Administrator
This is what I thought... If what you want to do is provide configuration to an external process, you can use the actionArgs parameters of the model to do this BUT you still need a transition to provide them to the agent. So you would have to come up with a state machine that would allow you to do this (but unclear what it will look like since you are not really changing the state: your app was running and is still running after the transition...).

Another solution is to treat configuration as a separate artifact with its own mountpoint and own glu script. You can tie it to the app by using the parent/child relationship. And you can change it independently of the app. That way you still get all the benefits from glu while achieving what you want to do. Treating configuration as its own artifact (properly version controlled), is very common in good devops practices.

Yan
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Property refresh without Bounce/Deploy/Redeploy

frenchyan
Administrator
In reply to this post by mrai
After more thinking, I may have find a solution which I just tested and it works perfectly and I think is actually really clean!​ No need for a new state machine! The idea is to have the config as a child of the parent.

Here is how it works (code available at this gist: https://gist.github.com/ypujante/7c9c1a74e77a9aeeb3e8)

First you have the glu script for your app in which you add a onConfigChanged closure that will be called by the child, like so (I have omitted all the other phases which are in charge of  downloading and starting your app... you obviously need to add them) :

class AppGluScript
{

  def onConfigChanged = { config ->
    log.info("From AppGluScript.onConfigChanged => ${config}")
  }

  // required for parent/child relationship
  def createChild = { args ->
    return args.script
  }

  // required for parent/child relationship
  def destroyChild = { args ->
  }
}

Then you have the glu script for the config of the app (this one is complete and probably does not need anything else):
class ConfigGluScript
{
  def configure = {
    log.info("From ConfigGluScript.configure")
    parent.onConfigChanged(params)
  }
}

Then in the model, you simply define the config as a parent of the app and the initParameters represent the configuration! Here is an example:

fabric = "glu-dev-1"
name = "Test Config (with parent/child)"

def agent = 'agent-1'

// app
entries << [
  agent: agent,
  mountPoint: "/app/i001",
  script: appScript,
]

// config for the app
entries << [
  agent: agent,
  mountPoint: "/app-config/i001",
  parent: "/app/i001", // tie to the parent
  script: configScript,
  initParameters: [
   p1: 'v1',
   p2: 34,
  ]
]

When you deploy you get a plan that looks like this:

Inline image 1

As you can see the configure phase of the child will run before the start phase of the app. This is what the agent log looks like:

2015/04/24 16:37:15.576 INFO [/app/i001] installScript([mountPoint:/app/i001, scriptLocation:http://localhost:8080/glu/repository/scripts/test-app-config/AppGluScript.groovy])
2015/04/24 16:37:15.647 INFO [/app/i001] clearError
2015/04/24 16:37:15.848 INFO [/app-config/i001] installScript([initParameters:[p2:34, p1:v1], parent:/app/i001, mountPoint:/app-config/i001, scriptLocation:http://localhost:8080/glu/repository/scripts/test-app-config/ConfigGluScript.groovy])
2015/04/24 16:37:15.850 INFO [/app/i001] executeAction([action:install, mountPoint:/app/i001, actionArgs:[:]]): 14cedcad74a-4f360cc8-2a60-4718-887b-b9c3fe73a333
2015/04/24 16:37:15.927 INFO [/app/i001] waitForState([state:installed, timeout:10s, mountPoint:/app/i001]): true
2015/04/24 16:37:16.068 INFO [/app-config/i001] clearError
2015/04/24 16:37:16.103 INFO [/app-config/i001] executeAction([action:install, mountPoint:/app-config/i001, actionArgs:[:]]): 14cedcad847-9350497c-6535-4ca8-be93-4481da6a5d26
2015/04/24 16:37:16.160 INFO [/app/i001] clearError
2015/04/24 16:37:16.163 INFO [/app-config/i001] waitForState([state:installed, timeout:10s, mountPoint:/app-config/i001]): true
2015/04/24 16:37:16.197 INFO [/app/i001] executeAction([action:configure, mountPoint:/app/i001, actionArgs:[:]]): 14cedcad8a5-6bd8117f-eced-47a2-aba8-3690b25e379e
2015/04/24 16:37:16.273 INFO [/app/i001] waitForState([state:stopped, timeout:10s, mountPoint:/app/i001]): true
2015/04/24 16:37:16.316 INFO [/app/i001] clearError
2015/04/24 16:37:16.344 INFO [/app/i001] executeAction([action:start, mountPoint:/app/i001, actionArgs:[:]]): 14cedcad938-7b59c451-7173-4679-8026-0cfda54b6668
2015/04/24 16:37:16.399 INFO [/app-config/i001] clearError
2015/04/24 16:37:16.449 INFO [/app-config/i001] executeAction([action:configure, mountPoint:/app-config/i001, actionArgs:[:]]): 14cedcad9a0-4ff9a914-b738-4bcf-a2f8-1f23ab46cada
2015/04/24 16:37:16.467 INFO [/app/i001] waitForState([state:running, timeout:10s, mountPoint:/app/i001]): true
2015/04/24 16:37:16.474 INFO [/app-config/i001] From ConfigGluScript.configure
2015/04/24 16:37:16.533 INFO [/app/i001] From AppGluScript.onConfigChanged => [p2:34, p1:v1]
2015/04/24 16:37:16.551 INFO [/app-config/i001] waitForState([state:stopped, timeout:10s, mountPoint:/app-config/i001]): true
2015/04/24 16:37:16.587 INFO [/app-config/i001] clearError
2015/04/24 16:37:16.616 INFO [/app-config/i001] executeAction([action:start, mountPoint:/app-config/i001, actionArgs:[:]]): 14cedcada47-32ee0a74-3b9e-4f53-8cc9-5ce5eb7d03f2
2015/04/24 16:37:16.690 INFO [/app-config/i001] waitForState([state:running, timeout:10s, mountPoint:/app-config/i001]): true


Now if you go in the mode and change the configuration (ex: p2 -> 100)

On the dashboard you get a delta!
Inline image 2
And the plan looks like this:
Inline image 3

As you can see it uninstall and reinstall the config ONLY without affecting the app. And this is what the agent log file looks like:
2015/04/24 16:39:11.054 INFO [/app-config/i001] clearError
2015/04/24 16:39:11.084 INFO [/app-config/i001] executeAction([action:stop, mountPoint:/app-config/i001, actionArgs:[:]]): 14cedcc996b-3c5c8dfa-429b-4244-9d91-d253b068a0e9
2015/04/24 16:39:11.154 INFO [/app-config/i001] waitForState([state:stopped, timeout:10s, mountPoint:/app-config/i001]): true
2015/04/24 16:39:11.185 INFO [/app-config/i001] clearError
2015/04/24 16:39:11.212 INFO [/app-config/i001] executeAction([action:unconfigure, mountPoint:/app-config/i001, actionArgs:[:]]): 14cedcc99ec-124d7c71-27e5-4168-96f0-7c71440ab5c7
2015/04/24 16:39:11.273 INFO [/app-config/i001] waitForState([state:installed, timeout:10s, mountPoint:/app-config/i001]): true
2015/04/24 16:39:11.314 INFO [/app-config/i001] clearError
2015/04/24 16:39:11.335 INFO [/app-config/i001] executeAction([action:uninstall, mountPoint:/app-config/i001, actionArgs:[:]]): 14cedcc9a66-78a53644-3736-4fe4-bd9f-ccb23d62bc53
2015/04/24 16:39:11.384 INFO [/app-config/i001] waitForState([state:NONE, timeout:10s, mountPoint:/app-config/i001]): true
2015/04/24 16:39:11.427 INFO [/app-config/i001] clearError
2015/04/24 16:39:11.491 INFO [/app-config/i001] uninstalled
2015/04/24 16:39:11.744 INFO [/app-config/i001] installScript([initParameters:[p2:100, p1:v1], parent:/app/i001, mountPoint:/app-config/i001, scriptLocation:http://localhost:8080/glu/repository/scripts/test-app-config/ConfigGluScript.groovy])
2015/04/24 16:39:11.883 INFO [/app-config/i001] clearError
2015/04/24 16:39:11.917 INFO [/app-config/i001] executeAction([action:install, mountPoint:/app-config/i001, actionArgs:[:]]): 14cedcc9cad-0f5295bb-a4c0-4300-bfbd-a289cb5a02ef
2015/04/24 16:39:11.979 INFO [/app-config/i001] waitForState([state:installed, timeout:10s, mountPoint:/app-config/i001]): true
2015/04/24 16:39:12.008 INFO [/app-config/i001] clearError
2015/04/24 16:39:12.046 INFO [/app-config/i001] executeAction([action:configure, mountPoint:/app-config/i001, actionArgs:[:]]): 14cedcc9d2b-9141115e-5dd8-4a81-836d-f8b9b3e97d1c
2015/04/24 16:39:12.081 INFO [/app-config/i001] From ConfigGluScript.configure
2015/04/24 16:39:12.087 INFO [/app/i001] From AppGluScript.onConfigChanged => [p2:100, p1:v1]
2015/04/24 16:39:12.114 INFO [/app-config/i001] waitForState([state:stopped, timeout:10s, mountPoint:/app-config/i001]): true
2015/04/24 16:39:12.154 INFO [/app-config/i001] clearError
2015/04/24 16:39:12.184 INFO [/app-config/i001] executeAction([action:start, mountPoint:/app-config/i001, actionArgs:[:]]): 14cedcc9db7-d510b761-90a5-45d4-8517-0421188f70fe
2015/04/24 16:39:12.262 INFO [/app-config/i001] waitForState([state:running, timeout:10s, mountPoint:/app-config/i001]): true

I really like this solution because it achieves what you want: be able to change the configuration without redeploying the app while still having the configuration in the system which triggers a delta when you change it. The delta is very lightweight since although it fully redeploy the config, really what happens is the initParameters change and the onConfigChanged gets called!

Hope this helps!
Yan
Loading...