Develop Cloud Applications for OpenStack on Murano, Day 4: The application, part 2: Creating the Murano App
In this series, we're looking at a very basic example, and we'll tell you all you need to make it work, but there are some great tutorials and references that describe this process (and more) in detail. You can find them in the official Murano documentation:So before we move on, let's just distill that down to the basics.
What we're ultimately trying to do
When we're all finished, what we want is basically a *.zip file structured in a way that Murano expects, with files that provide all of the information that it needs. There's nothing really magical about this process, it's just a matter of creating the various resources. In general, the structure of a Murano application looks something like this:.. |_ Classes | |_ PloneServer.yaml | |_ Resources | |_ scripts | |_ runPloneDeploy.sh | |_ DeployPloneServer.template | |_ UI | |_ ui.yaml | |_ logo.png | |_ manifest.yamlObviously the filenames (and content!) will depend on your specific application, but you get the idea. (If you'd like to see the finished version of this application, you can get it from GitHub.)
When we've assembled all of these pieces, we'll zip them up and they'll be ready to import into Murano.
Let's take a look at the individual pieces.
The individual files in a Murano package
Each of the individual files we're working with is basically just a text file.The Manifest file
The manifest.yaml file contains the main application’s information. For our PloneServerApp, that means the following:1. # Plone uses GPL version 2 as its license. As of summer 2009, there areLet’s start at Line 8:
2. # no active plans to upgrade to GPL version 3.
3. # You may obtain a copy of the License at
4. #
5. # http://www.gnu.org
6. #
7.
8. Format: 1.3
9. Type: Application
10. FullName: org.openstack.apps.plone.PloneServer
11. Name: Plone CMS
12. Description: |
13. The Ultimate Open Source Enterprise CMS.
14. The Plone CMS is one of the most secure
15. website systems available. This installer
16. lets you deploy Plone in standalone mode.
17. Requires Ubuntu 14.04 image with
18. preinstalled murano-agent.
19. Author: 'Evgeniy Mashkin'
20. Tags: [CMS, WCM]
21. Classes:
22. org.openstack.apps.plone.PloneServer: PloneServer.yaml
Format: 1.3
The versioning of the manifest format is directly connected with YAQL and the version of Murano itself. See the short description of format versions and choose the format version according to the OpenStack release you going to develop your application for. In our case, we're using Mirantis OpenStack 9.0, which is built on the Mitaka OpenStack release, so I chose the 1.3 version that corresponds to Mitaka.Now let’s move to Line 10:
FullName: org.openstack.apps.plone.PloneServer
Here you're adding a fully qualified name for your application, including the namespace if your choice.IMPORTANT: Don't use the io.murano namespace for your apps; it's being used for the Murano Core Library.
Lines 11 through 20 show the Name, Description, Author and Tags, which will be shown in the UI:
Name: Plone CMSFinally, on lines 21 and 22, you'll point to your application class file (which we'll build later). This file should be in the Classes directory of the package.
Description: |
The Ultimate Open Source Enterprise CMS. The Plone CMS is one of the most secure website systems available. This installer lets you deploy Plone in standalone mode. Requires Ubuntu 14.04 image with preinstalled murano-agent. Author: 'Evgeniy Mashkin' Tags: [CMS, WCM]
Classes: org.openstack.apps.plone.PloneServer: PloneServer.yamlMake sure to double check all of your references, filenames, and whitespaces as errors with these can cause errors when you upload your application package to Murano.
Execution Plan Template
The execution plan template -- DeployPloneServer.template -- describes the installation process of the Plone Server on a virtual machine and contains instructions to the murano-agent on what should be executed to deploy the application. Essentially, it tells Murano how to handle the runPloneDeploy.sh script we created yesterday.Here's the DeployPloneServer.template listing for our PloneServerApp:
1. # Plone uses GPL version 2 as its license. As of summer 2009, there are 2. # no active plans to upgrade to GPL version 3. 3. # You may obtain a copy of the License at 4. # 5. # http://www.gnu.org 6. # 7. FormatVersion: 2.0.0 8. Version: 1.0.0 9. Name: Deploy Plone 10. Parameters: 11. pathname: $pathname 12. password: $password 13. port: $port 14. Body: | 15. return ploneDeploy('{0} {1} {2}'.format(args.pathname, args.password, args.port)).stdout 16. Scripts: 17. ploneDeploy: 18. Type: Application 19. Version: 1.0.0 20. EntryPoint: runPloneDeploy.sh 21. Files: [] 22. Options: 23. captureStdout: true 24. captureStderr: trueStarting with lines 12 through 15, you can see that we're defining our parameters - the installation path, administrative password, and TCP port. Just as we added them on the command line yesterday, we need to tell Murano to ask the user for them.
Parameters: pathname: $pathname password: $password port: $portIn the Body section we have a string that describes the Python statement to execute, and how it will be executed by the Murano agent on the virtual machine:
Body: | return ploneDeploy('{0} {1} {2}'.format(args.pathname, args.password, args.port)).stdoutScripts defined in the Scripts section are invoked from here, so, we need to keep the order of arguments consistent with the runPloneDeploy.sh script that we developed yesterday.
Also, double check all filenames, whitespaces, and brackets. Mistakes here can cause the Murano agent to experience errors when it tries to run our installation script. If you do experience errors in this case, after an error has occurred, connect to the spawned VM via SSH and check the runPloneDeploy.log file we added for just this purpose.
Dynamic UI form definition
In order for the user to be able to add parameters such as the administrative password, we need to make sure that the user interface is set up correctly. We do this with the UI.yaml file, which contains the UI forms description that will be shown to users and tells users where they can set available installation options. The ui.yaml file for our PloneServerApp reads as follows:1. # Plone uses GPL version 2 as its license. As of summer 2009, there are 2. # no active plans to upgrade to GPL version 3. 3. # You may obtain a copy of the License at 4. # 5. # http://www.gnu.org 6. # 7. Version: 2.3 8. Application: 9. ?: 10. type: org.openstack.apps.plone.PloneServer 11. pathname: $.appConfiguration.pathname 12. password: $.appConfiguration.password 13. port: $.appConfiguration.port 14. instance: 15. ?: 16. type: io.murano.resources.LinuxMuranoInstance 17. name: generateHostname($.instanceConfiguration.unitNamingPattern, 1) 18. flavor: $.instanceConfiguration.flavor 19. image: $.instanceConfiguration.osImage 20. keyname: $.instanceConfiguration.keyPair 21. availabilityZone: $.instanceConfiguration.availabilityZone 22. assignFloatingIp: $.appConfiguration.assignFloatingIP 23. Forms: 24. - appConfiguration: 25. fields: 26. - name: license 27. type: string 28. description: GPL License, Version 2 29. hidden: true 30. required: false 31. - name: pathname 32. type: string 33. label: Installation pathname 34. required: false 35. initial: '/opt/plone/' 36. description: >- 37. Use to specify the top-level path for installation. 38. - name: password 39. type: string 40. label: Admin password 41. required: false 42. initial: 'admin' 43. description: >- 44. Enter administrative password for Plone. 45. - name: port 46. type: string 47. label: Port 48. required: false 49. initial: '8080' 50. description: >- 51. Specify the port that Plone will listen to 52. on available network interfaces. 53. - name: assignFloatingIP 54. type: boolean 55. label: Assign Floating IP 56. description: >- 57. Select to true to assign floating IP automatically. 58. initial: false 59. required: false 60. - name: dcInstances 61. type: integer 62. hidden: true 63. initial: 1 64. - instanceConfiguration: 65, fields: 66. - name: title 67. type: string 68. required: false 69. hidden: true 70. description: Specify some instance parameters on which the application would be created\ 71. - name: flavor 72. type: flavor 73. label: Instance flavor 74. description: >- 75. Select registered in Openstack flavor. Consider that 76. application performance depends on this parameter 77. requirements: 78. min_vcpus: 1 79. min_memory_mb: 256 80. required: false 81. - name: minrequirements 82. type: string 83. label: Minumum requirements 84. description: | 85. - Minimum 256 MB RAM and 512 MB of swap space per Plone site 86. - Minimum 512 MB hard disk space 87. hidden: true 88. required: false 89. - name: recrequirements 90. type: string 91. label: Recommended 92. description: | 93. - 2 GB or more RAM per Plone site 94. - 40 GB or more hard disk space 95. hidden: true 96. required: false 97. - name: osImage 98. type: image 99. imageType: linux 100. label: Instance image 101. description: >- 102. Select a valid image for the application. The image 103. should already be prepared and registered in Glance 104. - name: keyPair 105. type: keypair 106. label: Key Pair 107. description: >- 108. Select the Key Pair to control access to instances. You can login to 109. instances using this KeyPair after the deployment of application. 110. required: false 111. - name: availabilityZone 112. type: azone 113. label: Availability zone 114. description: Select availability zone where the application would be installed. 115. required: false 116. - name: unitNamingPattern 117. type: string 118. label: Instance Naming Pattern 119. required: false 120. maxLength: 64 121. regexpValidator: '^[a-zA-z][-_\w]*$' 122. errorMessages: 123. invalid: Just letters, numbers, underscores and hyphens are allowed. 124. helpText: Just letters, numbers, underscores and hyphens are allowed. 125. description: >- 126. Specify a string, that will be used in instance hostname. 127. Just A-Z, a-z, 0-9, dash and underline are allowed.This is a pretty long file, but it's not as complicated as it looks.
Starting at line 8:
Version: 2.3
The format version for the UI definition is optional and its default value is the latest supported version. If you want to use your application with one of the previous versions you may need to set the version field explicitly.Moving down the file, we basically have two UI forms: appConfiguration and instanceConfiguration.
Each form contains list of parameters that will be present on it. We place all of the parameters related to our Plone Server application on the appConfiguration form, including the path, password and TCP Port. This will then be sent to the Murano agent to invoke the runPloneDeploy.sh script:
- name: pathname type: string label: Installation pathname required: false initial: '/opt/plone/' description: >- Use to specify the top-level path for installation. - name: password type: string label: Admin password required: false initial: 'admin' description: >- Enter administrative password for Plone. - name: port type: string label: Port required: false initial: '8080' description: >- Specify the port that Plone will listen to on available network interfaces.For each parameter we also set initial values that will be used as defaults.
On the instanceConfiguration form, we’ll place all of the parameters related to instances that will be spawned during deployment. We need to set hardware limitations, such as minimum hardware requirements, in the requirements section:
- name: flavor type: flavor label: Instance flavor description: >- Select registered in Openstack flavor. Consider that application performance depends on this parameter requirements: min_vcpus: 1 min_memory_mb: 256 required: falseAlso, we need to add notices for users about minimum and recommended Plone hardware requirements on the UI form:
- name: minrequirements type: string label: Minumum requirements description: | - Minimum 256 MB RAM and 512 MB of swap space per Plone site - Minimum 512 MB hard disk space hidden: true required: false - name: recrequirements type: string label: Recommended description: | - 2 GB or more RAM per Plone site - 40 GB or more hard disk space
Murano PL Class Definition
Perhaps the most complicated part of the application is the class definition. Contained in PloneServer.yaml, it describes the methods the Murano agent must be able to execute in order to manage the application. In this case, the application class looks like this:1. # Plone uses GPL version 2 as its license. As of summer 2009, there are 2. # no active plans to upgrade to GPL version 3. 3. # You may obtain a copy of the License at 4. # 5. # http://www.gnu.org 6. # 7. Namespaces: 8. =: org.openstack.apps.plone 9. std: io.murano 10. res: io.murano.resources 11. sys: io.murano.system 12. Name: PloneServer 13. Extends: std:Application 14. Properties: 15. instance: 16. Contract: $.class(res:Instance).notNull() 17. pathname: 18. Contract: $.string() 19. password: 20. Contract: $.string() 21. port: 22. Contract: $.string() 23. Methods: 24. .init: 25. Body: 26. - $._environment: $.find(std:Environment).require() 27. deploy: 28. Body: 29. - If: not $.getAttr(deployed, false) 30. Then: 31. - $._environment.reporter.report($this, 'Creating VM for Plone Server.') 32. - $securityGroupIngress: 33. - ToPort: 80 34. FromPort: 80 35. IpProtocol: tcp 36. External: true 37. - ToPort: 443 38. FromPort: 443 39. IpProtocol: tcp 40. External: true 41. - ToPort: $.port 42. FromPort: $.port 43. IpProtocol: tcp 44. External: true 45. - $._environment.securityGroupManager.addGroupIngress($securityGroupIngress) 46. - $.instance.deploy() 47. - $resources: new(sys:Resources) 48. - $template: $resources.yaml('DeployPloneServer.template').bind(dict( 49. pathname => $.pathname, 50. password => $.password, 51. port => $.port 52. )) 53. - $._environment.reporter.report($this, 'Instance is created. Deploying Plone') 54. - $.instance.agent.call($template, $resources) 55. - $._environment.reporter.report($this, 'Plone Server is installed.') 56. - If: $.instance.assignFloatingIp 57. Then: 58. - $host: $.instance.floatingIpAddress 59. Else: 60. - $host: $.instance.ipAddresses.first() 61. - $._environment.reporter.report($this, format('Plone Server is available at http://{0}:{1}', $host, $.port)) 62. - $.setAttr(deployed, true)First we set the namespaces and class name, then define the parameters we'll be using later. We can then move into methods.
Besides the standard init method, our PloneServer class has one main method - deploy. It sets up instances of spawning and configuration. The deploy method performs the following tasks:
- It configures a security group and opens the TCP port 80, SSH port and our custom TCP port (as determined by the user):
- $securityGroupIngress: - ToPort: 80 FromPort: 80 IpProtocol: tcp External: true - ToPort: 443 FromPort: 443 IpProtocol: tcp External: true - ToPort: $.port FromPort: $.port IpProtocol: tcp External: true -$._environment.securityGroupManager.addGroupIngress($securityGroupIngress)
- It initiates the spawning of a new virtual machine:
- $.instance.deploy()
- It creates a Resources object, then loads the execution plan template (in the Resources directory) into it, updating the plan with parameters taken from the user:
- $resources: new(sys:Resources) - $template: $resources.yaml('DeployPloneServer.template').bind(dict( pathname => $.pathname, password => $.password, port => $.port ))
- It sends the ready-to-execute-plan to the murano agent:
- $.instance.agent.call($template, $resources)
- Lastly, it assigns a floating IP to the newly spawned machine, if it was chosen:
- If: $.instance.assignFloatingIp Then: - $host: $.instance.floatingIpAddress Else: - $host: $.instance.ipAddresses.first()
“The floating IP mechanism, besides exposing instances directly to the Internet, gives cloud users some flexibility. Having “grabbed” a floating IP from a pool, they can shuffle them (i.e., detach and attach them to different instances on the fly) thus facilitating new code releases and system upgrades. For sysadmins it poses a potential security risk, as the underlying mechanism (iptables) functions in a complicated way and lacks proper monitoring from the OpenStack side.”
Be aware that OpenStack is rapidly changing and some article’s statements may become obsolete, but the point is that there are advantages and disadvantages of using floating IPs.
Image File
In order to use OpenStack, you generally need an image to serve as the template for VMs you spawn. In some cases, those images will already be part of your cloud, but if not, you can specify them in the image.lst file. When you mention any image in this file and put it in your package, the image will be uploaded to your Cloud automatically. When importing images from the image.lst file, the client simply searches for a file with the same name as the name attribute of the image in the images directory of the package.An image file is optional, but to make sure your Murano App works you need to point any image with a pre-installed Murano agent. In our case it is Ubuntu 14.04 with a preinstalled Murano agent:
Images: - Name: 'ubuntu-14.04-m-agent.qcow2'
Hash: '393d4f2a7446ab9804fc96f98b3c9ba1' Meta: title: 'Ubuntu 14.04 x64 (pre-installed murano-agent)' type: 'linux' DiskFormat: qcow2 ContainerFormat: bare
Application Logo
The logo.png file is a preview image that will be visible to users in the application catalog. Having a logo file is optional, but for now, let’s choose this one:Create a Package
Finally, now that all the files are ready go to our package files directory (where the manifest.yaml file is placed) we can create a .zip package:$ zip -r org.openstack.apps.plone.PloneServer.zip *
Tomorrow we'll wrap up by showing you how to add your new package to the Murano application catalog.