Overview
Murano use packages to manage the launch and configuration of instances. This page will help you create your own package. Currently, Murano is using the Newton release. You can find official documentation for this release here.
You can see some packages as example here.
Introduction
Murano package must be in .zip form. The folder tree must look as follows :
The main parts of the package are the manifest file, the UI file, the classes file(s) and the ressources.
Manifest file
The manifest file will look like this:
-
Format : Please refer to the documentation
-
Type : Usually “Application”
-
FullName : Unique Application name. This name can be used by other packages to use the application methods.
-
Name : Display name in the UI
-
Description : Description to be shown in the UI
-
Author : Package author
-
Tags: Tags describing the package
-
Classes : Map class name(s) (To be called in the UI file) to class file(s)
UI file
UI files start with a version number
There are 2 main parts needed.
Template & Application
Simple example Jupyter
The Templates customJoinNet part will not change. It is needed on Genostack to get an IP in the instances
For basic packages, you only need the network.
Templates:
customJoinNet:
- ?:
type: io.murano.resources.ExistingNeutronNetwork
internalNetworkName: $.instanceConfiguration.network[0]
internalSubnetworkName: $.instanceConfiguration.network[1]
The Application part will link the UI to the class files. It needs to directly call a class name (defined in the manifest part) You will need to set here the variable needed by the class file
Application:
?:
type: myPackage.Jupyter # Class Name (defined in manifest).
password: $.instanceConfiguration.password # Refers to form instanceConfiguration, password field.
instance: # instance is a variable used in the class file. It need several properties.
?:
type: io.murano.resources.LinuxMuranoInstance # instance is a murano ressource.
flavor: $.instanceConfiguration.flavor # flavor variable refers to form instanceConfiguration, flavor field.
image: $.instanceConfiguration.osImage # Same for the following.
keyname: $.instanceConfiguration.keyPair
name: $.instanceConfiguration.name
networks: # That part will not change. It is need for network initialisation.
useEnvironmentNetwork: $.instanceConfiguration.network[0]=null
useFlatNetwork: false
customNetworks: switch($.instanceConfiguration.network[0], $=null=>list(), $!=null=>$customJoinNet)
More complex example (cluster)
If you want to create a cluster with one host, and several nodes, you will need to make a class for each type, and one additional class for orchestration. (So 3 classes) The orchestration class will go in the Application part, and the other two will go in the template part. Same as before, you will need to link each class to the UI.
Template part (Including Host and Node classes)
Templates:
customJoinNet:
- ?:
type: io.murano.resources.ExistingNeutronNetwork
internalNetworkName: $.hostConfiguration.network[0]
internalSubnetworkName: $.hostConfiguration.network[1]
host:
?:
type: myPackage.SGEHost #Link to the host class
host:
?:
type: io.murano.resources.LinuxMuranoInstance
flavor: m1.small
image: $.hostConfiguration.osImage
keyname: $.hostConfiguration.keyPair
name: $.hostConfiguration.name
networks:
useEnvironmentNetwork: $.hostConfiguration.network[0]=null
useFlatNetwork: false
customNetworks: switch($.hostConfiguration.network[0], $=null=>list(), $!=null=>$customJoinNet)
mednode:
?:
type: myPackage.SGEMedNode #Link to the node class
mednode:
?:
type: io.murano.resources.LinuxMuranoInstance
flavor: m1.medium
image: $.hostConfiguration.osImage #Use same option as host.
keyname: $.hostConfiguration.keyPair #Use same option as host.
name: generateHostname($.appConfiguration.unitNamingPattern, $index) #Generate hostname based on a pattern
networks:
useEnvironmentNetwork: $.hostConfiguration.network[0]=null
useFlatNetwork: false
customNetworks: switch($.hostConfiguration.network[0], $=null=>list(), $!=null=>$customJoinNet)
Application part
Application:
?:
type: myPackage.SGECluster #Link to orchestration class
host: $host # Set the variable host as the result of the host template
mednode: repeat($mednode, $.appConfiguration.maxnodeCount) # Set the variable node as the result of multiple node templates
Forms
The “Forms” part will create the user UI.
Each “form” in the Forms part will create a tab for the user to fill at application launch. You will have an additional windows to give the application a name.
You can set as much fields as you wish. You will need to set at least the flavor, image, keyname and name variables (either by letting the user setting it, or setting it yourself). Make sure to set all variables your application need.
- instanceConfiguration: #Name you will need to call to access the variables (ex : instanceConfiguration.title)
fields:
- name: title # Non interactive part, only to inform the user
type: string
required: false
hidden: true # The field will not be visible, only the description
description: Specify some instance parameters on which the application would be created
- name: name # Name of the variable
type: string # Variable type
initial: Jupyter # Initial value
label: Instance name # Label visible in the UI
maxLength: 64 # Max length
description: >-
Select your instance name.
- name: flavor
type: flavor # Special type : will show a dropdown list of available flavors
label: Instance flavor
description: >-
Select registered in Openstack flavor. Consider that application performance
depends on this parameter.
required: false
- name: osImage
type: image # Special type : will show a dropdown of images
imageType: jupyter # Will only show images with the "jupyter" metadata
label: Instance image
description: >-
Select valid image for the application. Image should already be prepared and
registered in glance.
- name: keyPair
type: keypair # Special type: will show the user available keypairs
label: Key Pair
description: >-
Select the Key Pair to control access to instances. You can login to
instances using this KeyPair after the deployment of application.
required: false
- name: password
type: password # Special type : string with constraint (complexity/length)
label: WebUI password
description: >-
Select the password wich will be used to connect to the web interface.
required: true
- name: network
type: network # Special type: Will show available networks
label: Network
description: Select a network to join. 'Auto' corresponds to a default environment's network.
required: false
allow_auto: false
murano_networks: translate
Ressources
Ressources are what you will need when the instance is launched. Meaning, scripts and data. Ressources need to be set as follow in your package, in the Resources folder
All your scripts need to be in the Resources/scripts folder. Scripts need to be called by a .template file. Each template file must contain at least a Body and Scripts part. You can also add a Parameters part if you need to pass parameters to your script.
Example of a template file:
FormatVersion: 2.0.0
Version: 1.0.0
Name: Deploy Master
Parameters: # Parameters passed by the class file
password: $password
hostName: $hostName
hostIP: $hostIP
nodesNamelist: $nodesNamelist
nodesIPlist: $nodesIPlist
Body: |
return hostDeploy('{0} {1} {2} {3} {4}'.format(args.password, args.hostName, args.hostIP, args.nodesNamelist, args.nodesIPlist)).stdout
# (Launch the hostDeploy script defined below, with the parameters)
Scripts:
hostDeploy:
Type: Application
Version: 1.0.0
EntryPoint: launch_Host.sh # The script to launch
Files:
- conf/slurm.conf # Files to include
Options:
captureStdout: true
captureStderr: true
You will manually call the template file in the class file. You can get the result of the script if needed.
Class file(s)
Namespaces
Namespaces are shortcut to call external classes
You will need to edit the “=:” part and the “Name” part so that the combination gives the Full Name written in the manifest
(Ex: myPackage.Jupyter)
Extends
You will need at least - std:Application in this part. You can import other classes here if you need.
Properties
Properties are variable that are needed to launch the application (for instance, a password, or an instance). These variable need to be set, either by the UI, or the orchestrator class.
Properties:
password: # Set in the UI
Contract: $.string().notNull() # Need to be a not null string
instance: # Set in te UI
Contract: $.class(res:Instance).notNull() # Need to be an instance
Methods
The initialize and deploy methods are automatically called. You should set up your environment in the initialize method, and setup the instance launch in the deploy method.
Methods:
initialize:
Body:
- $._environment: $.find(std:Environment).require() # Get the murano Environment class
- $resources: new(sys:Resources)
deploy:
Body:
- If: not $.getAttr(deployed, false) # Make sure it's not deployed yet
Then:
- $._environment.reporter.report($this, 'Creating VM') # Print a message
- $securityGroupIngress: # Define a new security group
- ToPort: 80 # Open port 80 & 443 to the outside
FromPort: 80
IpProtocol: tcp
External: true
- ToPort: 443
FromPort: 443
IpProtocol: tcp
External: true
- ToPort: 65535 # Open all port between instances in this application (ex:cluster)
IpProtocol: tcp
External: false
- $._environment.reporter.report($this, 'Adding security group')
- $._environment.securityGroupManager.addGroupIngress($securityGroupIngress) # Add the security group
- $._environment.reporter.report($this, 'Deploying')
- $.instance.deploy() # Deploy the instance
- $template: $resources.yaml('DeployJupyter.template').bind(dict(password => $.password)) #Prepare DeployJupyter.template with the variable $password
- $._environment.reporter.report($this, 'Instance is created. Launching Jupyter')
- $.instance.agent.call($template, $resources) # Launch template
- $.setAttr(deployed, true)
- $._address: $.instance.ipAddresses.first() # Get instance IP
- $._environment.reporter.report($this, 'Running on'+' '+str($._address))
This is a basic example : this script create a security group, launch an instance, and launch a script on it.
For a more complex example (multiple classes, deploy and pass variables between instances), please check here