使用murano的PL语言

本文介绍如何使用Murano进行应用部署,包括Murano包结构、Murano PL语言特性及常见用法,同时提供了安装Murano的方法和调试技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

声明:
本博客欢迎转载,但请保留原作者信息!
作者:柯晓东
团队:华为杭州OpenStack团队

转载自http://blog.youkuaiyun.com/canxinghen/article/details/61615823


最近在用Murano来部署应用,关于Murano包及PL语言的使用,这里总结一下,便于后来者。

先说Murano包,典型的Murano包如下图所示。含有UI的称为Application,它能继承library,但是不能被其他Application继承了。library不含UI,一般是平台提供,里面含有丰富的公共方法和属性。
这里写图片描述

UI目录 下放能自动生成表单的yaml文件。Murano之所以好用,是因为含有用文本描述的UI,以此可以在新接入一个组件时UI的活由新组件提供,非常适合平台和服务解耦。Murano通过yaml描述的UI也不是什么都能体现。指定某个输入框一定要输入字符串或一定要有值,这它是能做到的。但是下面这种场景它做不到:某radio button的值,为A时,几个输入框必须输入;为B时,同样的几个输入框可以不输入。
UI支持数字、字符串、布尔型,是否必选等基本类型,还支持通过glance、neutron选择镜像、虚拟网络,但是不支持选择物理主机。它支持的类型如下:

类型说明
stringDjango 字符串类型
booleanDjango 布尔类型
textDjango 文本类型
integerDjango 数字类型
password秘密类型
clusterip集群IP
floatingip外网Ip
domain域名
table表格
flavor规格
keypair密钥对
image镜像
azoneavailability zoom
imageType仅为镜像提供的属性


Resource目录 下放的是各式各样的脚本,这部分基本都和服务的实现有关。例如运行态的动态配置脚本,数据转换脚本等。

Classes目录 下放的是核心的yaml描述的部署文件。这些yaml就是用murano PL语言描述的类。这是这次介绍的核心部分。

Murano PL的类分为这么几部分:
1. 类名声明
2. 继承声明
3. 属性声明
4. 方法实现
前两部分和其他语言一样,就略过了。

属性声明的地方,主要涉及给变量起了名字后,要写什么类型,作用范围。如下图是典型的属性声明的代码段:
这里写图片描述

这里的Contract表示类型声明,下表是所有可用的类型:

类型说明
$.int()整形
$.string()字符串
$.string().notNull()非空字符串
$.bool()布尔类型(true/false) 0会被转为false,其他转为true
$.class(ns:ClassName)
$.class(ns:ClassName).notNull()非空类
$.class(ns:Name).check($.p = 12)类,并且含有名为p的属性,且值为12
$.template(ns:ClassName)模板声明,一般用于脚本调用使用
[$.int()]数组
[$.int().notNull()]数组
[$.string()]数组
[$.int().check($ > 0)]正数的数组
[$.int(), 2]数组长度至少为2
[$.int(), 2, 5]数组长度至少为2,至多为5
{ A: $.int(), B: [$.string()] }字典,key是int,value是字符串


Usage是用来声明作用域,可填的值如下:

属性类型说明
In输入参数,该参数只能通过UI设置,不能在MuranoPL代码里面修改。这是类属性的默认类型。
Out输出参数,该参数只能在MuranoPL代码里面修改,不能通过UI设置。
InOut既能由UI设置,又能在MuranoPL代码修改的参数。
Const和In类似,不同的是只能被用户设置一次。
Runtime和Out类似,不同的是不会被序列化。


然后就来到方法实现,Murano PL是一种用python解释的类yaml的语言,它有如下的约束:
1. 赋值用冒号,且冒号后要跟空格
2. 等号表示判断
3. 逗号不能在字符串内使用
4. 变量要用$作为前缀
5. 单个$ 就是java里面的this,而$xxx 表示变量xxx,$.xxx 表示类变量xxx

基本的代码片段如下:
(1) if语句

      - If: not $.getAttr(deployed, false)
        Then:
          - $.setAttr(deployed, true)
        Else:
          - $._environment.reporter.report($, "application has deployed")
  
  
  • 1
  • 2
  • 3
  • 4
  • 5

(2) for循环

      - For: applicationPort
        In: $applicationPorts.where($.scope != host)
        Do:
          - $._environment.reporter.report($, 'Configuring etcd node {0}'.format($applicationPort))
  
  
  • 1
  • 2
  • 3
  • 4

(3) while循环

      - $port: 1025
      - While: not $._checkIfPortIsNotUsed($port, $protocol)
        Do:
          $port: $port + 1
  
  
  • 1
  • 2
  • 3
  • 4

(4) 并发执行(可指定并发数)

          - Parallel:
              - $.node1.deployInstance()
              - $.node2.deployInstance()
              - $.node3.deployInstance()
              - $.node4.deployInstance()
              - $.node5.deployInstance()
              - $.node6.deployInstance()
          - Limit: 2
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

(5) switch语句

Switch:
  $predicate1():
    - code
    - block
  $predicate2():
    - code
    - block
Default:
  - code
  - block
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

(6)异常处理


Try:
  - code
  - block
Catch:
With: keyError
As: e
Do:
  - code
  - block
Else:
  - code
  - block
Finally:
  - code
  - block
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

(7)调用脚本

   - $resources: new(sys:Resources)
   - $template: $resources.yaml('DeployOrionChef.template').bind(dict( port => $.port))
   - $result: $.instance.agent.call($template, $resources)

  
  
  • 1
  • 2
  • 3
  • 4

(8)方法定义

  getTitle:
    Body:
      - Return: $.title

  checkIfPortUsed:
    Arguments:
      - port:
          Contract: $.int().notNull()
      - protocol:
          Contract: $.string().notNull()
    Body:
      - Return: len(list($.serviceEndpoints.where($.port = $port).where($.protocol = $protocol))) = 0
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12


常用的公共方法 如下:

方法说明
sleep(5)暂停5秒
now().year获取当前年份
id(xxx)取类实例的id
super(xxx)取类实例的父类
xxx.name获取组件名
typeinfo(xxx)获取实例类型
typeinfo(xxx).type获取类名
typeinfo(xxx).version获取版本
typeinfo(xxx).package获取包
typeinfo(xxx).ancestors获取类的父类
typeinfo(xxx).properties获取类所有属性。并可通过typeinfo(xxx).properties[i].getValue(xxx) 获取xxx对象的第i个属性的值
typeinfo(xxx).methods获取类所有方法,并可通过typeinfo(xxx).methods[i].invoke(xxx, ‘bar’, 2) 调用xxx对象第i个方法


常用的数组方法如下:

方法描述
[0, 1, 2].first()取数组的第一个元素
[0, 1, 2].last()取数组的最后一个元素
[0, 1, 2].len()查询数组长度
range(5).toList()产生0到4的数组
dict(a => 1, b => 2)定义字典
[1, 2, 3].append(4, 5)数组相加
{“a” => 1, “b” => 2}.items()字典转数组
[1, 2, 3, 4, 5].where($ > 3)取数组第3位开始的子集
isList([1, 2])判断是否是列表
isInteger(12.0)判断是否是整数
isNumber(12)判断是否数字
max(8, 2)取两者大者
min(8, 2)取两者小者


常用的字符串方法如下:

方法描述
str(123)数字转字符串
isString(1)判断是否是字符串
concat(“abc”, “de”, “f”)多个字符串合并
[“abc”, “de”, “f”].join(“|”)多个字符串合并
“|”.join([“abc”, “de”, “f”])多个字符串合并
“abc”.len()字符串长度
“aB1c”.toUpper()转大写
“AB1c”.toLower()转小写
“abc de f”.split()分割字符串
” abcd “.trim()去掉前后空格
“abaab”.replace(“ab”, “cd”)替换字符串
“abc{foo}ab{bar}abc”.format(foo => ” “, bar => “,”)用参数填充字符串
“cabcdab”.indexOf(“ab”, 2)从前往后查关键字
“cabcdab”.lastIndexOf(“ab”)从后往前查关键字
“abc de”.toCharArray()字符串转数组
“abcd”.startsWith(“ab”, “xx”)是否以特定字符串开头
“abcd”.endsWith(“cd”, “xx”)是否以特定字符串结尾


在预定义的基础公共类(core-library)中,最重要的是environment和instance。他们分别代表着运行环境和虚拟机对象。这两个类的常用属性如下:
(1) 环境(std:Environment)的属性

属性描述默认类型
name名字In
applicationsUI界面上能够显示出来的Application的列表。如果是new出来的对象,不在这个列表内。In
agentListener和Murano Agent通信的属性, io.murano.system.AgentListenerRuntime
stack和Heat交互用,常用的操作有current()、push()、updateTemplate($template)、setTemplate($template)Runtime
instanceNotifier获取部署实例时信息的类, io.murano.system.InstanceNotifierRuntime
defaultNetworks网络信息(io.murano.resources.Network).In
securityGroupManager安全组信息Runtime

(2) 实例(res:Instance)的属性

属性描述默认类型
namenova的实例名In
flavornova的套餐In
imageglance的景象In
keynamenova的keypairIn
agent和Murano Agent通信的属性io.murano.system.Agent.Runtime
ipAddressesIP地址列表的数组,如果有浮动IP,放置在列表末尾Out
networks虚拟机使用的网络In
volumes虚拟机使用的卷信息In
blockDevices如果从卷启动,需要指定(Volume class, device name, device type, boot order)In
assignFloatingIp是否需要指定浮动ip,默认False.In
floatingIpAddress浮动ip地址Out
securityGroupName安全组名In



其余还想知道的,可参看手册:http://murano.readthedocs.io/en/stable-liberty/appdev-guide/murano_pl.html


附1:用devstack在ubuntu安装murano。
(1)下载devstack
git clone https://git.openstack.org/openstack-dev/devstack
(2)配置apt-get使用阿里云的源(/etc/apt/sources.list)

deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse
##测试版源
deb http://mirrors.aliyun.com/ubuntu/ xenial-proposed main restricted universe multiverse
# 源码
deb-src http://mirrors.aliyun.com/ubuntu/ xenial main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse
##测试版源
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-proposed main restricted universe multiverse

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

(3)在devstack目录新建local.conf

[[local|localrc]]
LOGFILE=stack.sh.log
LOG_COLOR=False
DATABASE_PASSWORD=stack
RABBIT_PASSWORD=stack
SERVICE_TOKEN=stack
SERVICE_PASSWORD=stack
ADMIN_PASSWORD=stack

disable_service n-net
enable_service q-svc
enable_service q-agt
enable_service q-dhcp
enable_service q-l3
enable_service q-meta
enable_service q-lbaas
enable_service q-vpn
Q_PLUGIN=ml2
ENABLE_TENANT_VLANS=True
IP_VERSION=4
GIT_BASE=https://github.com
IMAGE_URLS=http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img

# Enable Horizon
disable_service tempest
enable_service horizon

# Enable Heat
enable_service heat h-api h-api-cfn h-api-cw h-eng

# Enable Murano
enable_plugin murano https://git.openstack.org/openstack/murano
enable_service murano murano-api murano-engine
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

(4)在devstack目录下,运行stack.sh安装murano

附2:murano PL调试方法
murano会在 /tmp/murano-package-cache目录下,为已经上传的包弄缓存。通过直接修改该目录下的文件,可以免除重新上传包的麻烦动作,改之后直接在UI上测试即可。


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值