Openstack Service Projects(Ocata)

https://releases.openstack.org/ocata/index.html

1
aodh  

ceilometer alarming
github
see: aodh

1
barbican 

Barbican 是 OpenStack 的key管理组件,定位在提供 REST API 来安全存储、提供和管理“秘密”。
architecture
see: what is barbican

1
ceilometer  

Ceilometer是OpenStack中的一个子项目,它像一个漏斗一样,能把OpenStack内部发生 的几乎所有的事件都收集起来,然后为计费和监控以及其它服务提供数据支撑。ceilometer被一分为四(Ceilometer、Gnocchi、Aodh、Panko),各司其职!其中Ceilometer负责采集计量数据并加工预处理;Gnocchi主要用来提供资源索引和存储时序计量数据;Aodh主要提供预警和计量通知服务;Panko主要提供事件存储服务。
architecture gnocchi

1
cinder  

block storage management

1
cloudkitty  

billing?

1
congress        

策略即服务? Congress 是云端开放的策略框架。云的操作者可以通过 Congress 在异构云环境中申报、监测、执行和审计“策略”。Congress 从云端不同的云服务中获取输入;例如在 OpenStack 中,Congress 从 Nova、Neutron 的网络状态中获取 VMs 信息。然后 Congress 会把这些输入数据从这些服务中输入到策略引擎当中,在那里 Congress 可以通过云运营商的政策来验证云端实际的状态。
Congress是一个基于异构云环境的策略声明、监控、实施、审计的框架(policy-as-a-service)。Congress从云中不同的服务获取数据,输入到congress的策略引擎,从而验证云中的各服务状态是否按照设置的策略运行。

1
designate 

Designate提供了DNSaaS(DNS即服务)的功能,其目标就是要赋予OpenStack提供这种云域名系统的能力,云服务商可以使用Designate就能够很容易建造一个云域名管理系统来托管租户的公有域名。
architecutre see: what is designate

1
freezer   

Freezer是一套开源的备份软件,它能帮助你自动的进行数据备份和还原动作。目前Freezer已正式引入OpenStack,从事数据备份,是OpenStack社区中一个官方项目,旨在为OpenStack提供数据备份环境的解决方案。
see: OpenStack云环境数据备份解决方案解析

1
glance 

Image management

1
heat        

OrchestrationService
Stack(栈): 在Heat领域,Stack是多个由Heat创建的对象或者资源的集合。它包含实例(虚拟机),网络,子网,路由,端口,路由端口,安全组(Security Group),安全组规则,自动伸缩等。
Template(模板): Heat使用template的概念来定义一个Stack. 如果你想要一个由私有网连接的2个实例,那么你的template需要包括2个实例,一个网络,一个子网和2个网络端口的定义。既然template是Heat工作的中心点,本文在后面将会展示一些例子。
Parameters(参数):Heat template有三个部分,而其中的一个就是要定义template的参数。参数包含一些基本信息,比如具体的镜像ID,或者特定网络ID。他们将由用户输入给template. 这种参数机制允许用户创建一个一般的template,它可能潜在使用不同的具体资源。
Resources(资源):Resource就是由Heat创建或者修改的具体的资源。它是Heat template的第二个重要部分。
Output(输出):Heat template的第三个和最后一个重要部分就是Output(输出)。它是通过OpenStack Dashboard或者Heat stack-list/stack-show命令来显示给用户。
HOT: Heat Orchestration Template的缩写,是Heat template使用的两种格式的一种。HOT并不与AWS CloudFormation template格式兼容,只能被OpenStack使用。HOT格式的template,通常但不是必须使用YAML。
CFN:AWS CloudFormation的缩写,Heat支持的第二种格式。CFN格式的template通常使用JSON。

1
horizon    

web ui

1
ironic 

baremetal management

1
keystone

auth

1
magnum  

Magnum 利用 Keystone, Nova, Heat, Neutron 等已有的 OpenStack组件,整合容器的 集群管理系统如 kubernetes, Mesos 等, 为用户更加简单灵活,多租户的容器服务
architecture deployment architecture
tutorial

1
manila  

Manila项目全称是File Share Service,文件共享即服务。是OpenStack大帐篷模式下的子项目之一,用来提供云上的文件共享,支持CIFS协议和NFS协议。

  1. 创建一个Nova实例,通过Cinder的Volume来提供NFS/CIFS共享服务
  2. 每个Share Network创建一个Nova实例
  3. 连接到已存在Neutron网络及子网中
  4. 创建Nova实例使用的Nova的flavor、Glance的image、SSH Keypair均是Manila配置的
  5. Manila通过 SSH对Nova实例进行配置
    workflow
    tutorail

1
mistral  

Mistral是mirantis公司为openstack开发的工作流组件,提供WorkFlow as a service。 典型的用户用例包括云平台的任务计划服务(Cloud Cron),任务调度(Task Scheduling), 复杂的运行时间长的业务流程服务。目前项目还在开始阶段。对应的是AWS的SWS(Simple WorkFlow Service)。
see: introduction

1
monasca-api 

1
monasca-log-api

monasca一个具有高性能,可扩展,高可用的监控即服务的(MONaas)解决方案。 使用Rest API接口来存储、查询性能和历史数据,不同与其他监控工具使用特殊的协议和传输方法,如nagios的NSCA,Monasca只利用了http。
多租户认证,指标的提交和认证使用Keystone组件。存储关联租户ID
指标使用(key,value)的键值来定义,称作量度(dimensions)
对系统指标进行实时阈值和告警
复合告警设置使用简单的语法,由子告警表达式和逻辑操作器组成
监控代理支持内置的系统和服务的检查结果,同时也只nagios的checks和statsd
根据开源技术搭建的开源监控方案
architecture
see: introduction

1
murano  

Murano是OpenStack的Application Catalog服务,推崇AaaS(Anything-as-a-Service)的概念,通过统一的框架和API实现应用程序快速部署和,用程序生命周期管理的功能,降低应用程序对底层平台(OpenStack层和虚拟化层)的依赖。 see: introduction
see: introduction

1
neutron  

network management

1
nova 

compute management, kvm/xen/esxi

1
panko 

Panko is designed to provide a metadata indexing, event storage service which enables users to capture the state information of OpenStack resources at a given time. Its aim is to enable a scalable means of storing both short and long term data for use cases such as auditing and system debugging.

1
sahara 

Sahara项目的目标是使用户能够在Openstack平台上一键式创建和管理Hadoop集群,实现类似AWS的EMR(Amazon Elastic MapReduce service)功能。用户只需要提供简单的配置参数和模板,如版本信息(如CDH版本)、集群拓扑(几个Slave,几个datanode)、节点配置信息(CPU、内存)等,Sahara服务就能够在几分钟时间内根据提供的模板快速部署Hadoop、Spark以及Storm集群。Sahara目支持节点的动态扩展(scalable),几乎所有插件支持扩容操作,部分插件还支持缩容,能够方便地按需增加或者减少节点数量,实现弹性大数据计算服务,适合开发人员或者QA在Openstack平台上快速部署大数据处理平台。
compents architecture
see: introduction

1
searchlight

Searchlight dramatically improves the user focused search capabilities and performance on behalf of various OpenStack cloud services.
concept overview
see: introduction

1
senlin  

Senlin是专为管理其他OpenStack服务中同类对象而设计的集群服务。它的特点在于拥有一个开放的框架,开发者能够为指定类型的对象提供插件以实现托管,以及在特定集群运行时想执行的策略。简而言之,它们能够为编程/管理OpenStack云提供一个阵列数据类型。

  1. 自动扩容
    Senlin有针对性的实现了跨可用Zone的部署、跨Region的部署、指定节点删除、手动扩容等功能。
  2. 负载均衡
    根据负载均衡policy,可以实现lb member的自动增加或者减少。
  3. 虚拟机HA
    虚拟机HA是一个企业级的功能,senlin会检测Node(虚拟机)的状态,当这个节点宕机时,会启用相关的recovery策略。
  4. 在Magnum中用来管理容器
    Senlin增加对Container的支持后在Magnum中就有了用武之地。东京峰会上腾对此有专题演讲:《Exploring Magnum and Senlin Integration for AutoScaling containers》
  5. 在Sahara中管理Handoop集群
    基于Ironic实现物理机的部署与管理。
    see: introduction

1
solum   

Solum是由Rackspace的工程师Adrian Otto于2013年9月在Launchpad上提出的一个BP。该项目聚焦于在OpenStack IaaS平台上,构建PaaS层的持续集成/持续交付(CI/CD)应用,可以简单理解为是一个应用程序App的集成开发平台。 components see: introduction

1
swift   

object storage

1
tacker  

Tacker是一个在OpenStack内部孵化的项目, 他的作用是NVF管理器,用于管理NVF的生命周期。 Tacker的重点是配置VNF, 并监视他们。如果需要,还可重启和/或扩展(自动修复)NVF。整个进程贯穿ETSIMANO所描述的整个生命周期。
architecture
workflow
see: introduction

1
tricircle

Tricircle is dedicated for networking automation across Neutron in multi-region OpenStack deployments. From the control plane view (cloud management view ), Tricircle is to make Neutron(s) in multi-region OpenStack clouds working as one cluster, and enable the creation of global network/router etc abstract networking resources across multiple OpenStack clouds. From the data plane view (end user resources view), all VMs(also could be bare metal servers or containers) are provisioned in different cloud but can be inter-connected via the global abstract networking resources, of course, with tenant level isolation.
introduction

1
trove   

对比Amazon AWS中各种关于数据的服务,其中最著名的是RDS(SQL-base)和DynamoDB(NoSQL),除了实现了基本的数据管理能力,还具备良好的伸缩能力、容灾能力和不同规格的性能表现。因此,对于最炙手可热的开源云计算平台Openstack来说,也从Icehouse版加入了DBaaS服务,代号Trove。“Trove is Database as a Service for OpenStack. It’s designed to run entirely on OpenStack, with the goal of allowing users to quickly and easily utilize the features of a relational or non-relational database without the burden of handling complex administrative tasks. ”
1、动态resize能力
分为instance-resize和volume-resize,前者主要是实例运行的内存大小和cpu核数,后者主要是指数据库分区对应的硬盘卷的大小。由于实例是跑在vm上的,而vm的cpu和memory的规格可以通过Nova来进行动态调整,所以调整是非常方便快捷的。另外硬盘卷也是由Cinder提供的动态扩展功能来实现resize。resize过程中服务会有短暂的中断,是由于mysqld重启导致的。
2、全量与增量备份
目前mysql的实现中,备份是由实例vm上的guestagent运行xtrabackup工具进行备份,且备份后的文件会存储在Swift对象存储中。从备份创建实例的过程则相反。由于xtrabackup强大的备份功能,所以Trove要做的只是做一些粘胶水的工作。
3、动态配置更新
目前支持实例的自定义配置,可以创建配置组应该到一组实例上,且动态attach到运行中的实例中生效。
4、一主多从的一键创建
在创建数据库实例的API中,支持批量创建多个从实例,并以指定的实例做主进行同步复制。这样就方便了从一个已有实例创建多个从实例的操作。而且mysql5.6版本之后的同步复制支持GTID二进制日志,使得主从实例之间关系的建立更加可靠和灵活,在failover处理上也更加快速。
5、集群创建与管理(percona/mariadb支持)
Cluster功能目前在mysql原生版本暂时不支持,但是其两个分支版本percona和mariadb基于Galera库实现的集群复制技术是支持的。另外Liberty版本的Trove也提供了对mongodb的集群支持。
architecture
use case
see: introduction

1
vitrage  

Vitrage is the Openstack RCA (Root Cause Analysis) Engine for organizing, analyzing and expanding OpenStack alarms & events, yielding insights regarding the root cause of problems and deducing the existence of problems before they are directly detected.
see: introduction

1
watcher   

Watcher为OS提供资源优化。主要是通过虚拟机迁移来提高整个数据中心的运营效率,降低TCO。 watcher
see: policy
see: what is watcher

1
zaqar

Zaqar is a multi-tenant cloud messaging and notification service for web and mobile developers.

aggregates

测试版本:Fuel(9.0.0) openstack(Mitaka)

what’s aggregates in nova

Aggregates是在 OpenStack 的 Regions 和 Availability Zones 之后被提出来,并建立于 Availability Zones 基础之上更进一步划分 computes 节点物理资源的一种机制。

Availability Zones 通常是对 computes 节点上的资源在小的区域内进行逻辑上的分组和隔离。例如在同一个数据中心,我们可以将 Availability Zones 规划到不同的机房,或者在同一机房的几个相邻的机架,从而保障如果某个 Availability Zone 的节点发生故障(如供电系统或网络),而不影响其他的 Availability Zones 上节点运行的虚拟机,通过这种划分来提高 OpenStack 的可用性。目前 OpenStack 默认的安装是把所有的 computes 节点划分到 nova 的 Availability Zone 上。

Host Aggregates 是在 Availability Zones 的基础上更进一步地进行逻辑的分组和隔离。例如我们可以根据不同的 computes 节点的物理硬件配置将具有相同共性的物理资源规划在同一 Host Aggregate 之下,或者根据用户的具体需求将几个 computes 节点规划在具有相同用途的同一 Host Aggregate 之下,通过这样的划分有利于提高 OpenStack 资源的使用效率。使用场景如下:

  1. 在具有相同物理特性的 computes 节点上创建 Host Aggregate, 比如下面将具有高性能CPU的 computes 节点规划为一组,并将 Host Aggregate 命名为“cpu/xeon-e7”。
  2. 覆盖nova.conf的配置, eg:ram_allocation_ratio/AggregateRamFilter

img img img

az对用户是可见的,aggregates只对程序可见,由nova-scheduler使用。

查看nova源码下的ls scheduler/filters

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
affinity_filter.py
aggregate_image_properties_isolation.py
aggregate_instance_extra_specs.py
aggregate_multitenancy_isolation.py
all_hosts_filter.py
availability_zone_filter.py
compute_capabilities_filter.py
compute_filter.py
core_filter.py
disk_filter.py
exact_core_filter.py
exact_disk_filter.py
exact_ram_filter.py
extra_specs_ops.py
image_props_filter.py
io_ops_filter.py
isolated_hosts_filter.py
json_filter.py
metrics_filter.py
numa_topology_filter.py
num_instances_filter.py
pci_passthrough_filter.py
ram_filter.py
retry_filter.py
trusted_filter.py
type_filter.py

1
nova help | grep 'aggregate

1
2
3
4
5
6
7
8
9
10
aggregate-add-host          Add the host to the specified aggregate.
aggregate-create            Create a new aggregate with the specified
aggregate-delete            Delete the aggregate.
aggregate-details           Show details of the specified aggregate.
aggregate-list              Print a list of all aggregates.
aggregate-remove-host       Remove the specified host from the specified
                            aggregate.
aggregate-set-metadata      Update the metadata associated with the
                            aggregate.
aggregate-update            Update the aggregate's name and optionally

1
nova help aggregate-create

1
2
3
4
5
6
7
usage: nova aggregate-create <name> [<availability-zone>]

Create a new aggregate with the specified details.

Positional arguments:
  <name>               Name of aggregate.
  <availability-zone>  The availability zone of the aggregate (optional).

新建一个aggregate

1
root@node-6:~# nova availability-zone-list    
1
root@node-6:~# nova service-list

1
2
3
4
5
+----+------------------+--------------------+----------+---------+-------+----------------------------+-----------------+
| Id | Binary           | Host               | Zone     | Status  | State | Updated_at                 | Disabled Reason |
+----+------------------+--------------------+----------+---------+-------+----------------------------+-----------------+
| 8  | nova-compute     | node-4.suninfo.com | nova     | enabled | up    | 2017-02-15T03:10:51.000000 | -               |
+----+------------------+--------------------+----------+---------+-------+----------------------------+-----------------+

1
root@node-6:~# nova aggregate-create cpu/xeon-e7 nova

如果没有指定 Availability Zone, OpenStack 会将 Host Aggregate 建在默认的 Availability Zone 下面(如 nova),否则会根据指定的名字来判断是否创建新的 Availability Zone 或使用已经存在的 Availability Zone,同时在此之下创建 Host Aggregate。

1
2
3
4
5
+----+-------------+-------------------+-------+--------------------------+
| Id | Name        | Availability Zone | Hosts | Metadata                 |
+----+-------------+-------------------+-------+--------------------------+
| 12 | cpu/xeon-e7 | nova              |       | 'availability_zone=nova' |
+----+-------------+-------------------+-------+--------------------------+

1
root@node-6:~# nova hypervisor-list

1
2
3
4
5
+----+---------------------+-------+---------+
| ID | Hypervisor hostname | State | Status  |
+----+---------------------+-------+---------+
| 1  | node-4.suninfo.com  | up    | enabled |
+----+---------------------+-------+---------+

1
root@node-6:~# nova aggregate-add-host cpu/xeon-e7 node-4.suninfo.com

1
2
3
4
5
6
Host node-4.suninfo.com has been successfully added for aggregate 12 
+----+-------------+-------------------+----------------------+--------------------------+
| Id | Name        | Availability Zone | Hosts                | Metadata                 |
+----+-------------+-------------------+----------------------+--------------------------+
| 12 | cpu/xeon-e7 | nova              | 'node-4.suninfo.com' | 'availability_zone=nova' |
+----+-------------+-------------------+----------------------+--------------------------+

启动vm并指定计算节点,只需要az功能即可实现, az对用户是可见的。如果希望做一些调度优化,那么就需要管理员通过aggregates来实现。

1
root@node-6:~# nova boot  --image 027e7611-c85f-4097-8d66-eab63f620987 --flavor m1.micro --nic net-id=a18d722f-1edf-4e17-a86d-a96c45fcaaaf --availability-zone nova:node-4.suninfo.com  az-test-vm

确认添加AggregateInstanceExtraSpecsFilter到nova.conf的scheduler_default_filters

整合aggregates和flavor, 选择flavor后自动调度到相应的aggregates meta匹配的计算节点

1
root@node-6:~# nova aggregate-set-metadata cpu/xeon-e7 cpu=xeon-e7

1
2
3
4
5
6
Metadata has been successfully updated for aggregate 12.
+----+-------------+-------------------+----------------------+-----------------------------------------+
| Id | Name        | Availability Zone | Hosts                | Metadata                                |
+----+-------------+-------------------+----------------------+-----------------------------------------+
| 12 | cpu/xeon-e7 | nova              | 'node-4.suninfo.com' | 'cpu=xeon-e7', 'availability_zone=nova' |
+----+-------------+-------------------+----------------------+-----------------------------------------+

1
root@node-6:~# nova flavor-create cpu.xeon-e7 auto 4096 10 2

1
root@node-6:~# nova flavor-key cpu.xeon-e7 set aggregate_instance_extra_specs:cpu=xeon-e7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
+----------------------------+--------------------------------------+
| Property                   | Value                                |
+----------------------------+--------------------------------------+
| OS-FLV-DISABLED:disabled   | False                                |
| OS-FLV-EXT-DATA:ephemeral  | 0                                    |
| disk                       | 10                                   |
| extra_specs                | {"aggregate_instance_extra_specs:cpu": "xeon-e7"}              |
| id                         | 11224306-e4df-483b-9a1f-5c35c47a5584 |
| name                       | cpu.xeon-e7                          |
| os-flavor-access:is_public | True                                 |
| ram                        | 4096                                 |
| rxtx_factor                | 1.0                                  |
| swap                       |                                      |
| vcpus                      | 2                                    |
+----------------------------+--------------------------------------+

再创建一个测试用的flavor,规格相同,extra_specs不同

1
root@node-6:~# nova flavor-create cpu.xeon-e5 auto 4096 10 2
1
root@node-6:~# nova flavor-key cpu.xeon-e5 set aggregate_instance_extra_specs:cpu=xeon-e5

测试,通过flavor启动vm

1
nova boot  --image 027e7611-c85f-4097-8d66-eab63f620987 --flavor cpu.xeon-e5 --nic net-id=a18d722f-1edf-4e17-a86d-a96c45fcaaaf   aggregate-test-vm

1
| 5048dbaf-6d24-4c46-a496-2d670dbb59c8 | aggregate-test-vm | ERROR  | -          | NOSTATE     |                                                   |

1
nova boot  --image 027e7611-c85f-4097-8d66-eab63f620987 --flavor cpu.xeon-e7 --nic net-id=a18d722f-1edf-4e17-a86d-a96c45fcaaaf   aggregate-test-vm

1
| 056dba3d-b3a3-409e-a193-35506981c0ef | aggregate-test-vm | ACTIVE | -          | Running     | admin_internal_net=192.168.111.121                |

flavor cpu.xeon-e5的vm创建失败,flavor cpu.xeon-e7的vm创建成功,aggregate生效。

warning

1
root@node-6:~# nova aggregate-add-host cpu/xeon-e5 node-4.suninfo.com

ERROR (Conflict): Cannot add host to aggregate 12. Reason: One or more hosts already in availability zone(s) [u’nova’]. (HTTP 409) (Request-ID: req-81aa55b5-0bb2-47e1-89c2-4d64ac9c9a8c)

一个nova-compute节点只能在一个az内,但是可以存在多个aggregate内。

1
ComputeCapabilitiesFilter
也会使用flavor的extra-specs去和host-state的属性做对比,所以flavor的extra-spece key需要根据一定的规则跳过ComputeCapabilitiesFilter的检查, key名称用此格式”TYPE:KEY”, type只要不等于”capabilities”即可跳过

1
AggregateInstanceExtraSpecsFilter
的metadata key也需要一些规则约束,key名称使用格式flavor extra-specs中的”aggregate_instance_extra_specs:KEY”中的KEY部分

一个计算节点属于多个aggregate,并且具有相同的metadata key,那么这个host的key对应的值为set集合,匹配规则为任一个满足即可。

ATTENTION

  1. Resize/Migrate时都需要重新scheduler,所以需要避免在高性能物理服务器上的vm调度到普通机器上。
  2. ComputeCapabilitiesFilter在N版本之前存在bug(#1582589),最好禁用,否则只能用特殊的flavor.metadata key(上面有key格式说明)。N版本已经Fix此bug

REFERENCES:
host-aggregate

how to use cloud-init

inside vm(ubuntu1404)

1
$ apt-cache search cloud-init

1
cloud-init - Init scripts for cloud instances

1
$ sudo apt-get --download-only install cloud-init

1
f9215960baf8de0e59e0e81844d8e9dc  cloud-init_0.7.5-0ubuntu1.21_all.deb

1
root@first-vm:/usr/lib/python2.7/dist-packages/cloudinit# which cloud-init

1
/usr/bin/cloud-init

1
root@first-vm:/usr/lib/python2.7/dist-packages/cloudinit# which cloud-init-per 

1
/usr/bin/cloud-init-per

1
root@first-vm:/usr/lib/python2.7/dist-packages/cloudinit# cloud-init -h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
usage: cloud-init [-h] [--version] [--file FILES] [--debug] [--force]
                  {init,modules,query,single} ...

positional arguments:
  {init,modules,query,single}
    init                initializes cloud-init and performs initial modules
    modules             activates modules using a given configuration key
    query               query information stored in cloud-init
    single              run a single module

optional arguments:
  -h, --help            show this help message and exit
  --version, -v         show program's version number and exit
  --file FILES, -f FILES
                        additional yaml configuration files to use
  --debug, -d           show additional pre-action logging (default: False)
  --force               force running even if no datasource is found (use at
                        your own risk)

1
root@first-vm:/usr/lib/python2.7/dist-packages/cloudinit# cloud-init-per -h     

1
2
3
4
5
6
7
8
9
10
Usage: cloud-init-per frequency name cmd [ arg1 [ arg2 [ ... ] ]
   run cmd with arguments provided.

   This utility can make it easier to use boothooks or bootcmd
   on a per "once" or "always" basis.

   If frequency is:
      * once: run only once (do not re-run for new instance-id)
      * instance: run only the first boot for a given instance-id
      * always: run every boot

/etc/cloud/cloud.cfg

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# The top level settings are used as module
# and system configuration.

# A set of users which may be applied and/or used by various modules
# when a 'default' entry is found it will reference the 'default_user'
# from the distro configuration specified below
users:
   - default

# If this is set, 'root' will not be able to ssh in and they 
# will get a message to login instead as the above $user (ubuntu)
disable_root: true

# This will cause the set+update hostname module to not operate (if true)
preserve_hostname: false

# Example datasource config
# datasource: 
#    Ec2: 
#      metadata_urls: [ 'blah.com' ]
#      timeout: 5 # (defaults to 50 seconds)
#      max_wait: 10 # (defaults to 120 seconds)

# The modules that run in the 'init' stage
cloud_init_modules:
 - migrator
 - seed_random
 - bootcmd
 - write-files
 - growpart
 - resizefs
 - set_hostname
 - update_hostname
 - update_etc_hosts
 - ca-certs
 - rsyslog
 - users-groups
 - ssh

# The modules that run in the 'config' stage
cloud_config_modules:
# Emit the cloud config ready event
# this can be used by upstart jobs for 'start on cloud-config'.
 - emit_upstart
 - disk_setup
 - mounts
 - ssh-import-id
 - locale
 - set-passwords
 - grub-dpkg
 - apt-pipelining
 - apt-configure
 - package-update-upgrade-install
 - landscape
 - timezone
 - puppet
 - chef
 - salt-minion
 - mcollective
 - disable-ec2-metadata
 - runcmd
 - byobu

# The modules that run in the 'final' stage
cloud_final_modules:
 - rightscale_userdata
 - scripts-vendor
 - scripts-per-once
 - scripts-per-boot
 - scripts-per-instance
 - scripts-user
 - ssh-authkey-fingerprints
 - keys-to-console
 - phone-home
 - final-message
 - power-state-change

# System and/or distro specific settings
# (not accessible to handlers/transforms)
system_info:
   # This will affect which distro class gets used
   distro: ubuntu
   # Default user name + that default users groups (if added/used)
   default_user:
     name: ubuntu
     lock_passwd: True
     gecos: Ubuntu
     groups: [adm, audio, cdrom, dialout, dip, floppy, netdev, plugdev, sudo, video]
     sudo: ["ALL=(ALL) NOPASSWD:ALL"]
     shell: /bin/bash
   # Other config here will be given to the distro class and/or path classes
   paths:
      cloud_dir: /var/lib/cloud/
      templates_dir: /etc/cloud/templates/
      upstart_dir: /etc/init/
   package_mirrors:
     - arches: [i386, amd64]
       failsafe:
         primary: http://archive.ubuntu.com/ubuntu
         security: http://security.ubuntu.com/ubuntu
       search:
         primary:
           - http://%(ec2_region)s.ec2.archive.ubuntu.com/ubuntu/
           - http://%(availability_zone)s.clouds.archive.ubuntu.com/ubuntu/
           - http://%(region)s.clouds.archive.ubuntu.com/ubuntu/
         security: []
     - arches: [armhf, armel, default]
       failsafe:
         primary: http://ports.ubuntu.com/ubuntu-ports
         security: http://ports.ubuntu.com/ubuntu-ports
   ssh_svcname: ssh

cloud-init-output.log

1
$ cat cloud-init-output.log | grep running

1
2
3
4
Cloud-init v. 0.7.5 running 'init-local' at Tue, 21 Feb 2017 03:23:04 +0000. Up 3.76 seconds.
Cloud-init v. 0.7.5 running 'init' at Tue, 21 Feb 2017 03:23:06 +0000. Up 5.73 seconds.
Cloud-init v. 0.7.5 running 'modules:config' at Tue, 21 Feb 2017 03:23:17 +0000. Up 16.48 seconds.
Cloud-init v. 0.7.5 running 'modules:final' at Tue, 21 Feb 2017 03:23:23 +0000. Up 23.06 seconds.

cloud-init by manually

1
root@first-vm:/usr/lib/python2.7/dist-packages/cloudinit# cloud-init --debug init

cloud-init init 默认只init执行一次, semaphore位置/var/lib/cloud/instance/obj.pkl,/var/lib/cloud/data/no-net

1
root@first-vm:/usr/lib/python2.7/dist-packages/cloudinit# cloud-init single -n cc_xx

1
2
3
4
# args = Namespace(action=('single', <function main_single at 0x7fc67f9112a8>), debug=False, files=None, force=False, frequency=None, module_args=[], name='cc_xx')
Cloud-init v. 0.7.5 running 'single' at Tue, 21 Feb 2017 07:33:47 +0000. Up 15047.18 seconds.
2017-02-21 07:33:48,019 - stages.py[WARNING]: Could not find module named cc_xx
2017-02-21 07:33:48,020 - cloud-init[WARNING]: Did not run cc_xx, does it exist?

1
cloud-init --debug modules -m config (repeat running log show below)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Feb 21 08:06:53 first-vm [CLOUDINIT] helpers.py[DEBUG]: config-disk_setup already ran (freq=once-per-instance)
Feb 21 08:06:53 first-vm [CLOUDINIT] helpers.py[DEBUG]: config-mounts already ran (freq=once-per-instance)
Feb 21 08:06:53 first-vm [CLOUDINIT] helpers.py[DEBUG]: config-ssh-import-id already ran (freq=once-per-instance)
Feb 21 08:06:53 first-vm [CLOUDINIT] helpers.py[DEBUG]: config-locale already ran (freq=once-per-instance)
Feb 21 08:06:53 first-vm [CLOUDINIT] helpers.py[DEBUG]: config-set-passwords already ran (freq=once-per-instance)
Feb 21 08:06:53 first-vm [CLOUDINIT] helpers.py[DEBUG]: config-grub-dpkg already ran (freq=once-per-instance)
Feb 21 08:06:53 first-vm [CLOUDINIT] helpers.py[DEBUG]: config-apt-pipelining already ran (freq=once-per-instance)
Feb 21 08:06:53 first-vm [CLOUDINIT] helpers.py[DEBUG]: config-apt-configure already ran (freq=once-per-instance)
Feb 21 08:06:53 first-vm [CLOUDINIT] helpers.py[DEBUG]: config-package-update-upgrade-install already ran (freq=once-per-instance)
Feb 21 08:06:53 first-vm [CLOUDINIT] helpers.py[DEBUG]: config-landscape already ran (freq=once-per-instance)
Feb 21 08:06:53 first-vm [CLOUDINIT] helpers.py[DEBUG]: config-timezone already ran (freq=once-per-instance)
Feb 21 08:06:53 first-vm [CLOUDINIT] helpers.py[DEBUG]: config-puppet already ran (freq=once-per-instance)
Feb 21 08:06:53 first-vm [CLOUDINIT] helpers.py[DEBUG]: config-chef already ran (freq=once-per-instance)
Feb 21 08:06:53 first-vm [CLOUDINIT] helpers.py[DEBUG]: config-salt-minion already ran (freq=once-per-instance)
Feb 21 08:06:53 first-vm [CLOUDINIT] helpers.py[DEBUG]: config-mcollective already ran (freq=once-per-instance)

1
cloud-init --debug modules -m final

/var/lib/cloud/scripts/

1
root@first-vm:/var/lib/cloud/scripts/per-boot# tree /var/lib/cloud/

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/var/lib/cloud/
├── data
│   ├── instance-id
│   ├── previous-datasource
│   ├── previous-hostname
│   ├── previous-instance-id
│   ├── result.json
│   └── status.json
├── handlers
├── instance
│   └── boot-finished
├── instances
│   └── db97088f-55f3-4997-8519-f028cc3764c0
│       ├── cloud-config.txt
│       ├── datasource
│       ├── handlers
│       ├── obj.pkl
│       ├── scripts
│       ├── sem
│       │   ├── config_apt_configure
│       │   ├── config_apt_pipelining
│       │   ├── config_byobu
│       │   ├── config_ca_certs
│       │   ├── config_chef
│       │   ├── config_disk_setup
│       │   ├── config_grub_dpkg
│       │   ├── config_keys_to_console
│       │   ├── config_landscape
│       │   ├── config_locale
│       │   ├── config_mcollective
│       │   ├── config_mounts
│       │   ├── config_package_update_upgrade_install
│       │   ├── config_phone_home
│       │   ├── config_power_state_change
│       │   ├── config_puppet
│       │   ├── config_rightscale_userdata
│       │   ├── config_rsyslog
│       │   ├── config_runcmd
│       │   ├── config_salt_minion
│       │   ├── config_scripts_per_instance
│       │   ├── config_scripts_user
│       │   ├── config_scripts_vendor
│       │   ├── config_seed_random
│       │   ├── config_set_hostname
│       │   ├── config_set_passwords
│       │   ├── config_ssh
│       │   ├── config_ssh_authkey_fingerprints
│       │   ├── config_ssh_import_id
│       │   ├── config_timezone
│       │   ├── config_users_groups
│       │   ├── config_write_files
│       │   └── consume_data
│       ├── user-data.txt
│       ├── user-data.txt.i
│       ├── vendor-data.txt
│       └── vendor-data.txt.i
├── scripts
│   ├── per-boot
│   │   └── test.sh
│   ├── per-instance
│   ├── per-once
│   └── vendor
├── seed
└── sem
    └── config_scripts_per_once.once

1
root@first-vm:/var/lib/cloud/scripts/per-boot# ll /var/lib/cloud/scripts/per-boot/

1
2
3
4
5
6
# chmod +X
-rwxr-xr-x 1 root root   62 Feb 23 03:07 test.sh*

# content
#!/bin/sh
echo "test echo"

code

1
2
# stage.Init.paths
self.paths: {'lookups': {'cloud_config': 'cloud-config.txt', 'userdata': 'user-data.txt.i', 'vendordata': 'vendor-data.txt.i', 'userdata_raw': 'user-data.txt', 'boothooks': 'boothooks', 'scripts': 'scripts', 'sem': 'sem', 'data': 'data', 'vendor_scripts': 'scripts/vendor', 'handlers': 'handlers', 'obj_pkl': 'obj.pkl', 'vendordata_raw': 'vendor-data.txt', 'vendor_cloud_config': 'vendor-cloud-config.txt'}, 'template_tpl': '/etc/cloud/templates/%s.tmpl', 'cfgs': {'cloud_dir': '/var/lib/cloud/', 'templates_dir': '/etc/cloud/templates/', 'upstart_dir': '/etc/init/'}, 'cloud_dir': '/var/lib/cloud/', 'datasource': <cloudinit.sources.DataSourceOpenStack.DataSourceOpenStack object at 0x7fe148080610>, 'upstart_conf_d': '/etc/init/', 'boot_finished': '/var/lib/cloud/instance/boot-finished', 'instance_link': '/var/lib/cloud/instance', 'seed_dir': '/var/lib/cloud/seed'}

业务场景

  1. install by vagrant
  2. configuration
  3. minion target pattern
  4. salt modules
  5. custom modules
  6. salt state
  7. salt http api

launch saltstack by vagrant

1. install by vagrant

$ cat Vagrantfile

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
34
35
36
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|

  config.vm.define :node1 do |node1|
        node1.vm.box = "ubuntu1404"
        node1.vm.hostname = "salt-master"
        node1.vm.network :private_network, :ip => "172.16.200.100"
        node1.vm.network "public_network",:bridge => "eth0", auto_config: false
        node1.vm.synced_folder ".", "/vagrant", disabled: true
        node1.vm.provision "shell", inline: "apt-get install -y salt-master"
  end

  config.vm.define :node2 do |node2|
        node2.vm.box = "ubuntu1404"
        node2.vm.hostname = "salt-minion"
        node2.vm.network :private_network, :ip => "172.16.200.101"
        node2.vm.network "public_network",:bridge => "eth0", auto_config: false
        node2.vm.synced_folder ".", "/vagrant", disabled: true
        node2.vm.provision "shell", inline: "apt-get install -y salt-minion"
  end

  config.vm.provider "virtualbox" do |vb|
        vb.gui = false
        vb.customize ["modifyvm", :id, "--memory", "1024"]
        vb.customize ["modifyvm", :id, "--ioapic", "on"]
        vb.customize ["modifyvm", :id, "--cpus", "2"]
        #vb.customize ["modifyvm", :id, "--nic2", "intnet"]
        #vb.customize ["modifyvm", :id, "--nictype2", "Am79C973"]
  end

  config.vm.provision "shell" do |shell|
        shell.path = "./setup.sh"
  end
end

$ cat setup.sh

1
2
3
4
5
6
#!/bin/bash

echo "deb http://mirrors.163.com/ubuntu/ trusty main restricted universe multiverse" > /etc/apt/sources.list
cat /etc/apt/sources.list
ping -c 4 114.114.114.114
apt-get update

$ vagrant up

注意,最好安装salt的最新release版本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apt-get install software-properties-common python-software-properties
sudo add-apt-repository ppa:saltstack/salt2015-5
apt-get install -y salt-master

salt --versions-report

              Salt: 2015.5.3
            Python: 2.7.6 (default, Mar 22 2014, 22:59:56)
            Jinja2: 2.7.2
          M2Crypto: 0.21.1
    msgpack-python: 0.3.0
      msgpack-pure: Not Installed
          pycrypto: 2.6.1
           libnacl: Not Installed
            PyYAML: 3.10
             ioflo: Not Installed
             PyZMQ: 14.0.1
              RAET: Not Installed
               ZMQ: 4.0.4
              Mako: 0.9.1
           Tornado: Not Installed
Debian source package: 2015.5.3+ds-1trusty1

2. config master/monion

at minion node, config salt master host and self id

1
2
3
4
5
$ root@salt-minion:~# vi /etc/salt/minion
    # master: **salt-master**
    # id: **salt-minion**

$ root@salt-minion:~# service salt-minion restart

at master node, validate salt-key

1
2
3
# list all salt minion keys status
$ root@salt-master:~# salt-key
# show fingerprients

如果/etc/salt/master中auto_accept不是True,那么需要手动签名

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
34
35
36
37
38
39
40
root@salt-master:~# tree /etc/salt/
/etc/salt/
├── master
├── master.d
│   └── salt-api.conf
└── pki
    └── master
        ├── master.pem
        ├── master.pub
        ├── minions
        ├── minions_autosign
        ├── minions_denied
        ├── minions_pre
        │   └── salt-minion  ### HERE
        └── minions_rejected


$ root@salt-master:~# salt-key -f salt-minion
# accept the key at master

$ root@salt-master:~# salt-key -a salt-minion 

# delete key
salt-key -d MINION

root@salt-master:~# tree /etc/salt/
/etc/salt/
├── master
├── master.d
│   └── salt-api.conf
└── pki
    └── master
        ├── master.pem
        ├── master.pub
        ├── minions
        │   └── salt-minion  ### HERE
        ├── minions_autosign
        ├── minions_denied
        ├── minions_pre
        └── minions_rejected

test it!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ root@salt-master:~# salt '*' test.ping
$ root@salt-master:~# salt 'salt-minion' sys.doc test.ping

test.ping:

    Just used to make sure the minion is up and responding
    Return True

    CLI Example:

        salt '*' test.ping

root@salt-master:~# salt 'salt-minion' sys.list_functions | wc -l
603
root@salt-master:~# salt 'salt-minion' sys.list_modules | wc -l
66

3. target pattern

Usage: salt [options]

1
'<target>'
1
<function>
1
[arguments]

3.1 global matching

target = ‘host-name’
target = ‘
target = ‘my

target = ‘my*client’
target = ‘my??client’
target = ‘my[a-z]client’

3.2 PCRE

target = -E

1
'<exp>'

3.3 list matching

target = -L

1
'a, b, c'

3.4 grains

target = –grain ‘os_familiy:RedHat’
target = -G ‘os:Ubuntu’
target = -G ‘os:centos*’

salt ‘*’ grains.items
cat /etc/salt/grains
3.5 pillar

TODO

3.6 compound matching

target = -C

1
'*minion and G@os:Ubuntu and not L@yourminion,theirminion'

target = -C
1
'* and not G@os_family:RedHat'

1
2
3
4
5
6
7
8
Letter  Match Type          Example
G       Grains glob         G@os:Ubuntu
E       PCRE minion ID      E@web\d+\.(dev|qa|prod)\.loc
P       Grains PCRE         P@os:(RedHat|Fedora|CentOS)
L       List of minions     L@minion1.example.com, minion3.domain.com
I       Pillar glob         I@pdata:foobar
S       Subnet/IP address   S@192.168.1.0/24 or S@192.168.1.100
R       Range cluster       R@%foo.bar

4. moduels

1
2
3
4
5
6
7
8
salt '*' sys.list_modules
salt '*' sys.doc user.add  
salt '*' user.info <User>  
salt '*' sys.doc pkg.install  
salt '*' pkg.install apache2
salt '*' service.status apache2
salt '*' status.diskusage
salt '*' cmd.run 'echo HELLO'

5. exploring the modules

1
# get the source code

1
2
git clone https://github.com/saltstack/salt.git
ls -l salt/modules

1
__salt__

    call = __salt__['cmd.run_all'](cmd,
output_loglevel='trace',
python_shell=False)

1
__virtual__

    # Define the module's virtual name
__virtualname__ = 'pkg'


def __virtual__():
'''
Confirm this module is on a Debian based system
'''

if __grains__.get('os_family', False) == 'Kali':
return __virtualname__
elif __grains__.get('os_family', False) == 'Debian':
return __virtualname__
return False

1
__opts__

1
# see: salt/modules/config.py
    def option(
value,
default='',
omit_opts=False,
omit_master=False,
omit_pillar=False):
'''
Pass in a generic option and receive the value that will be assigned

CLI Example:

.. code-block:: bash

salt '*' config.option redis.host
'''

if not omit_opts:
if value in __opts__:
return __opts__[value]
if not omit_master:
if value in __pillar__.get('master', {}):
return __pillar__['master'][value]
if not omit_pillar:
if value in __pillar__:
return __pillar__[value]
if value in DEFAULTS:
return DEFAULTS[value]
return default

1
__pillar__

1
# TODO
5.1 custom moduels

By defualt, custom modeuls path live in

1
/srv/salt/_modules
, create it by manual.

The first custom module, eonstack

1
salt '*' eonstack.run_qos
5.1.1 write python code
1
cat /srv/salt/_modules/eonstack.py
    # -*- coding: utf-8 -*-

from __future__ import absolute_import

# Import python libs
import os
import logging
import json

# Import third party libs
import yaml


# Define the module's virtual name
__virtualname__ = 'eonstack'


def __virtual__():
'''
Confirm this module is on a Debian based system
'''

if __grains__.get('os_family', False) == 'Kali':
return __virtualname__
elif __grains__.get('os_family', False) == 'Debian':
return __virtualname__

return __virtualname__

def echo(text):
'''
Return a string - used for testing the connection

CLI Example:

.. code-block:: bash

salt '*' test.echo 'foo bar baz quo qux'
'''

return text


5.1.2 sync custom modules to all minion
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
salt '*' saltutl.sync_util 
[root@salt-master _modules]# salt '*' saltutil.sync_all
salt-client1:
    ----------
    beacons:
    grains:
    modules:
        - modules.eonstack
    outputters:
    renderers:
    returners:
    states:
    utils:
salt-master:
    ----------
    beacons:
    grains:
    modules:
        - modules.eonstack
    outputters:
    renderers:
    returners:
    states:
    utils:
5.1.3 test it!
1
[root@salt-master _modules]# salt '*' eonstack.echo 'hello world'

6. State

By default, states are located in the /srv/salt driectory. All Salt-specific files that aren’t Python files and in the extension .sls.

1
2
3
4
5
6
7
# list all state modules
salt "Minion" sys.list_state_modules
# show state function
salt "Mionion" sys.list_state_functions <STATE>
# help
salt 'Minion' sys.state_doc <STATE>
salt 'Minion' sys.state_doc <STATE.func> 
6.1 first example
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# cat /srv/salt/git.sls
root@node-1:/srv/salt# cat /srv/salt/git.sls 
---
install_git:
  pkg.installed:
    -
      name: git


# run it
root@node-1:/srv/salt# salt 'node-3*' state.sls git
node-3.domain.tld:
----------
    State: - pkg
    Name:      git
    Function:  installed
        Result:    True
        Comment:   Package git is already installed
        Changes:

Summary
------------
Succeeded: 1
Failed:    0
------------
Total:     1

# remove git package and rerun the states
root@node-1:/srv/salt# salt 'node-3*' pkg.remove git

root@node-1:/srv/salt# salt 'node-3*' state.sls git
node-3.domain.tld:
----------
    State: - pkg
    Name:      git
    Function:  installed
        Result:    True
        Comment:   The following packages were installed/updated: git.
        Changes:   git: { new : 1:1.9.1-1ubuntu0.1
                        old :
                        }
                   git-core: { new : 1
                        old :
                        }
                   git-completion: { new : 1
                        old :
                        }


Summary
------------
Succeeded: 1
Failed:    0
------------
Total:     1

List the functions for a given state module with sys.list_functions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
root@node-1:/srv/salt# salt 'node-3*' sys.list_functions pkg

node-3.domain.tld:
    - pkg.available_version
    - pkg.del_repo
    - pkg.expand_repo_def
    - pkg.file_dict
    - pkg.file_list
    - pkg.get_repo
    - pkg.get_selections
    - pkg.install
    - pkg.latest_version
    - pkg.list_pkgs
    - pkg.list_repos
    - pkg.list_upgrades
    - pkg.mod_repo
    - pkg.purge
    - pkg.refresh_db
    - pkg.remove
    - pkg.set_selections
    - pkg.upgrade
    - pkg.upgrade_available
    - pkg.version
    - pkg.version_cmp

state declaration is called:

1
2
3
4
5
6
7
8
<ID Declaration>:
    <State Module>.<Function>:
    - name: <name>
    - <Function Arg>
    - <Function Arg>
    - <Function Arg>
    - <Requisite Declaration>:
        - <Requisite Reference>

7. HTTP REST API

在master结点安装restapi

1
apt-get install -y salt-api

构造ssl key

1
2
openssl genrsa -out /root/salt-api/key.pem 4096
openssl req -new -x509 -key /root/salt-api/key.pem -out /root/salt-api/cert.pem -days 1826

编辑rest server的配置文件如下rest_cherrypy

1
2
3
4
5
6
7
8
9
root@salt-master:/etc/salt/master.d# cat /etc/salt/master.d/salt-api.conf
rest_cherrypy:
  port: 8080
  host: 172.16.200.100
  ssl_crt: /root/salt-api/cert.pem
  ssl_key: /root/salt-api/key.pem
  webhook_disable_auth: True
  webhook_url: /hook
  collect_stats: True

创建API用户

1
2
3
groupadd eonstack
useradd -g eonstack -M -s /user/sbin/nologin -c 'saltstack rest api user for eonboard' eonstack
passwd eonstack

设置salt-api验证用户的类型

1
2
3
4
5
6
7
8
# cat /etc/salt/master

# The external auth system uses the Salt auth modules to authenticate and
# validate users to access areas of the Salt system.
external_auth:
  pam:
    eonstack:
      - .*

重启服务

1
service salt-master restart && service salt-api restart

验证API

1
2
3
4
5
6
7
8
9
10
11
url_map = {
    'index': LowDataAdapter,
    'login': Login,
    'logout': Logout,
    'minions': Minions,
    'run': Run,
    'jobs': Jobs,
    'keys': Keys,
    'events': Events,
    'stats': Stats,
}
index(GET/POST)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# GET
curl --insecure https://172.16.200.100:8080/index/ -H 'Accept: application/x-yaml' -d username='eonstack' -d password='password' -d eauth='pam' -X GET
clients:
- _is_master_running
- local
- local_async
- local_batch
- runner
- runner_async
- ssh
- ssh_async
- wheel
- wheel_async
return: Welcome

# POST
curl --insecure https://172.16.200.100:8080/index/ -H 'Accept: application/x-yaml' -H 'X-Auth-Token : badf65223c19084464a8e9315e5900a0efc100df' -d client=local -d tgt='*' -d fun=test.ping -X POST
return:
- salt-minion: true
login (GET/POST)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# GET
curl --insecure https://172.16.200.100:8080/login/ -H 'Accept: application/x-yaml' -d username='eonstack' -d password='password' -d eauth='pam' -X GET
return: Please log in
status: null

# POST
curl --insecure https://172.16.200.100:8080/login/ -H 'Accept: application/x-yaml' -d username='eonstack' -d password='password' -d eauth='pam' -X POST
return:
- eauth: pam
  expire: 1445633027.415278
  perms:
  - .*
  start: 1445589827.415275
  token: badf65223c19084464a8e9315e5900a0efc100df
  user: eonstack
logout (POST)
1
2
3
# POST
curl --insecure https://172.16.200.100:8080/logout/ -H 'Accept: application/x-yaml' -H 'X-Auth-Token : badf65223c19084464a8e9315e5900a0efc100df' -X POST
return: Your token has been cleared
minions (GET/POST)
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
# GET 
curl --insecure https://172.16.200.100:8080/minions/ -H 'Accept: application/x-yaml' -H 'X-Auth-Token : 1e975aadb3149374c9e6d5c481b925845e736f2c' -X GET
return:
- salt-minion:
    grains.items 

# GET BY not exist ID
curl --insecure https://172.16.200.100:8080/minions/not-exists/ -H 'Accept: application/x-yaml' -H 'X-Auth-Token : 1e975aadb3149374c9e6d5c481b925845e736f2c' -X GET
return:
- {}

# GET BY ID
curl --insecure https://172.16.200.100:8080/minions/salt-minion/ -H 'Accept: application/x-yaml' -H 'X-Auth-Token : 1e975aadb3149374c9e6d5c481b925845e736f2c' -X GET
return:
- salt-minion:
    grains.items 

# POST
curl --insecure https://172.16.200.100:8080/minions/ -H 'Accept: application/x-yaml' -H 'X-Auth-Token : 1e975aadb3149374c9e6d5c481b925845e736f2c' -X POST -d tgt='*' -d fun='status.diskusage'
_links:
  jobs:
  - href: /jobs/20151023090633311442
return:
- jid: '20151023090633311442'
  minions:
  - salt-minion 
jobs (GET)
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# GET JOB
curl --insecure https://172.16.200.100:8080/jobs/20151023092345571347 -H 'Accept: application/x-yaml' -H 'X-Auth-Token : 4b01221fea2d1ec7026cf087a11724dbb7e44017' -X GET

info:
- Arguments: []
  Function: status.diskusage
  Minions:
  - salt-minion
  Result:
    salt-minion:
      return:
        /:
          available: 38232371200
          total: 41612050432
        /dev:
          available: 1038528512
          total: 1038532608
        /dev/pts:
          available: 0
          total: 0
 StartTime: 2015, Oct 23 09:23:45.571347
  Target: '*'
  Target-type: glob
  User: eonstack
  jid: '20151023092345571347'
return:
- salt-minion:
    /:
      available: 38232371200
      total: 41612050432
    /dev:
      available: 1038528512
      total: 1038532608
    /dev/pts:


# GET JOB by not exist id
root@salt-minion:~# curl --insecure https://172.16.200.100:8080/jobs/xxx -H 'Accept: application/x-yaml' -H 'X-Auth-Token : 4b01221fea2d1ec7026cf087a11724dbb7e44017' -X GET
info:
- Arguments: []
  Function: unknown-function
  Result: {}
  StartTime: ''
  Target: unknown-target
  Target-type: []
  User: root
  jid: xxx
return:
- {}
run(POST)

need: user/password at the post body every tim

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# POST
curl --insecure https://172.16.200.100:8080/run -H 'Accept: application/json' -d username='eonstack' -d password='password' -d eauth='pam' -d client='local' -d tgt='*' -d fun='test.ping'
{"return": [{"salt-minion": true}]}

# POST
curl --insecure https://172.16.200.100:8080/run/ -H 'Accept: application/x-yaml' -d username='eonstack' -d password='password' -d eauth='pam' -d client='local' -d tgt='*' -d fun='test.fib' -d arg=10
return:
- salt-minion:
  - - 0
    - 1
    - 1
    - 2
    - 3
    - 5
    - 8
  - 4.0531158447265625e-06

events(GET)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 监听事件 - 命令行
$ salt-run state.event pretty=True

# 监听事件 - HTTP Keep-alive
$ curl -G -NsS --insecure https://10.6.14.212:8080/events -H "X-Auth-Token: 7e2a7e82876a36f1b6d4289f2561d80f2ef29ad4"
retry: 400
tag: salt/event/new_client
data: {"tag": "salt/event/new_client", "data": {"_stamp": "2015-11-11T10:14:11.295501"}}

# 监听事件 by python
resp = requests.get("https://10.6.14.212:8080/events", verify=False, headers={'X-Auth-Token': '99c5dc46bdff4c40ca3e31b2f90291fe87518cee'}, stream=True)
for line in resp.iter_lines():
    if(line):
        print line

reference

  1. SALT TABLE OF CONTENTS

Influxdb

InfluxDB is a time series, metrics, and analytics database. It’s written in Go and has no external dependencies.

key features

  • SQL-like query language.
  • HTTP(S) API for data ingestion and queries.
  • Built-in support for other data protocols such as collectd.
  • Store billions of data points.
  • Tag data for fast and efficient queries.
  • Database-managed retention policies for data.
  • Built in management interface.
  • Aggregate on the fly:

    SELECT mean(value) FROM cpu_user WHERE cpu=cpu6 GROUP BY time(5m)`

  • Store and query hundreds of thousands of series, filtering by tags:

    SELECT mean(value) FROM cpu WHERE region=”uswest” AND az=”1” AND server=”server01” GROUP BY time(30s)

  • Merge multiple series together:

    SELECT mean(value) FROM /cpu.*/ WHERE time > now() - 1h GROUP BY time(30m)

install

1
2
3
4
wget http://influxdb.s3.amazonaws.com/influxdb_0.9.4.2_amd64.deb
sudo dpkg -i influxdb_0.9.4.2_amd64.deb

$ service influxdb restart

first database

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
root@fabric-tools:~# /opt/influxdb/influx
> help
Usage:
        connect <host:port>   connect to another node
        auth                  prompt for username and password
        pretty                toggle pretty print
        use <db_name>         set current databases
        format <format>       set the output format: json, csv, or column
        consistency <level>   set write consistency level: any, one, quorum, or all
        settings              output the current settings for the shell
        exit                  quit the influx shell

        show databases        show database names
        show series           show series information
        show measurements     show measurement information
        show tag keys         show tag key information
        show tag values       show tag value information

        a full list of influxql commands can be found at:
        https://influxdb.com/docs/v0.9/query_language/spec.html

expected SELECT, DELETE, SHOW, CREATE, DROP, GRANT, REVOKE, ALTER, SET

1
2
3
4
5
6
7
8
9
10
11
> create database mydb

> show databases
name: databases
---------------
name
_internal
mydb

> use mydb
Using database mydb

write

insert [series],tag1=value,tag2=value2 filed1=f1,filed2=f2

Time series have zero to many points, one for each discrete sample of the metric. Points consist of time (a timestamp), a measurement (“cpu_load”), at least one key-value field (the measured value itself, e.g. “value=0.64” or “15min=0.78”), and zero to many key-value tags containing metadata (e.g. “host=server01”, “region=EMEA”, “dc=Frankfurt”). Conceptually you can think of a measurement as an SQL table, with rows where the primary index is always time. tags and fields are effectively columns in the table. tags are indexed, fields are not. The difference is that with InfluxDB you can have millions of measurements, you don’t have to define schemas up front, and null values aren’t stored.

1
2
3
4
5
6
7
8
9
# 空格不能乱用!
> insert cpu, host=node-1, region=beijing value=0.64
ERR: unable to parse 'cpu, host=node-1, region=beijing value=0.64': missing tag key

> insert cpu, host=node-1,region=beijing value=0.64
ERR: unable to parse 'cpu, host=node-1,region=beijing value=0.64': missing tag key

> insert cpu,host=node-1,region=beijing value=0.64
>

query

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
> select * from /.*/ LIMIT 1

> select * from cpu
name: cpu
---------
time                            host    region  value
2015-11-05T03:29:15.626447374Z  node-1  beijing 0.64

> select * from memory where  value>80000
name: memory
------------
time                            host    region  value
2015-11-05T03:31:41.316307173Z  node-1  beijing 102400
2015-11-05T03:31:54.729084653Z  node-1  beijing 92400
2015-11-05T03:32:01.856464936Z  node-1  beijing 82400

> select * from memory where  value>90000
name: memory
------------
time                            host    region  value
2015-11-05T03:31:41.316307173Z  node-1  beijing 102400
2015-11-05T03:31:54.729084653Z  node-1  beijing 92400

HTTP API

  • ping
  • query
  • write

Ports:

1
8086 HTTP
,
1
8083 WebUI
,
1
8088 Heartbeat

Warning:
1
--data-urlencode
1
--data-binary

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
# ping
$ curl -sl -I localhost:8086/ping

# create database by API
$ curl -I -G -X GET http://10.6.14.210:8086/query --data-urlencode "q=CREATE DATABASE api_db"
HTTP/1.1 200 OK
Content-Type: application/json
Request-Id: e0d3607e-8382-11e5-804a-000000000000
X-Influxdb-Version: 0.9.4.2
Date: Thu, 05 Nov 2015 06:03:04 GMT
Content-Length: 16

# write data by post body
$ curl -i -X POST "http://10.6.14.210:8086/write?db=mydb" --data-binary "cpu,host=node-c,region=xian value=1234"
HTTP/1.1 204 No Content
Request-Id: df23c983-8384-11e5-8055-000000000000
X-Influxdb-Version: 0.9.4.2
Date: Thu, 05 Nov 2015 06:17:20 GMT

# write data by file
$ curl -i -X POST "http://10.6.14.210:8086/write?db=mydb" --data-binary @cpu_data.txt
HTTP/1.1 204 No Content
Request-Id: 8f5e69d9-8385-11e5-8059-000000000000
X-Influxdb-Version: 0.9.4.2
Date: Thu, 05 Nov 2015 06:22:16 GMT

$ cat cpu_data.txt                                                                   
cpu,host=nova-6,region=jinan value=1234
cpu,host=nova-8,region=jinan value=1234
cpu,host=nova-9,region=jinan value=1234
cpu,host=nova-10,region=jinan value=1234
cpu,host=nova-11,region=jinan value=1234

NOTE: Appending pretty=true to the URL enables pretty-printed JSON output. While this is useful for debugging or when querying directly with tools like curl, it is not recommended for production use as it consumes unnecessary network bandwidth.

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# query data
$ curl -iG "http://10.6.14.210:8086/query?pretty=true" --data-urlencode "db=mydb" --data-urlencode "q=select * from cpu;"
HTTP/1.1 200 OK
Content-Type: application/json
Request-Id: 26437b67-8387-11e5-8066-000000000000
X-Influxdb-Version: 0.9.4.2
Date: Thu, 05 Nov 2015 06:33:39 GMT
Content-Length: 1948

{
    "results": [
        {
            "series": [
                {
                    "name": "cpu",
                    "columns": [
                        "time",
                        "host",
                        "region",
                        "value"
                    ],
                    "values": [
                        [
                            "2015-11-05T03:29:15.626447374Z",
                            "node-1",
                            "beijing",
                            0.64
                        ],
                        [
                            "2015-11-05T06:17:20.725547255Z",
                            "node-c",
                            "xian",
                            1234
                        ],
                        [
                            "2015-11-05T06:22:16.3887656Z",
                            "nova-11",
                            "jinan",
                            1234
                        ],
                        [
                            "2015-11-05T06:22:16.3887656Z",
                            "nova-6",
                            "jinan",
                            1234
                        ]
                    ]
                }
            ]
        }
    ]
}

# multi query in one api call

HTTP/1.1 200 OK
Content-Type: application/json
Request-Id: 44b9b0aa-8388-11e5-806d-000000000000
X-Influxdb-Version: 0.9.4.2
Date: Thu, 05 Nov 2015 06:41:39 GMT
Transfer-Encoding: chunked

{
    "results": [
        {
            "series": [
                {
                    "name": "instance",
                    "columns": [
                        "time",
                        "flavor",
                        "used",
                        "value",
                        "zone"
                    ],
                    "values": [
                        [
                            "2015-11-05T03:35:04.153222973Z",
                            "m1.tniy",
                            null,
                            10,
                            "nova"
                        ],
                        [
                            "2015-11-05T03:43:06.488054254Z",
                            "m1.tniy",
                            11,
                            10,
                            "nova"
                        ]
                    ]
                }
            ]
        },
        {
            "series": [
                {
                    "name": "memory",
                    "columns": [
                        "time",
                        "host",
                        "region",
                        "value"
                    ],
                    "values": [
                        [
                            "2015-11-05T03:31:41.316307173Z",
                            "node-1",
                            "beijing",
                            102400
                        ],
                        [
                            "2015-11-05T03:52:00.539433556Z",
                            "node-2",
                            "shanghai",
                            9000
                        ]
                    ]
                }
            ]
        }
    ]
}

# query with error
$ curl -iG "http://10.6.14.210:8086/query?db=mydb" --data-urlencode "q=selec * from instance;" --data-urlencode "pretty=true" 
HTTP/1.1 400 Bad Request
Content-Type: application/json
Request-Id: a4a44f96-8388-11e5-8072-000000000000
X-Influxdb-Version: 0.9.4.2
Date: Thu, 05 Nov 2015 06:44:20 GMT
Content-Length: 141

{
    "error": "error parsing query: found selec, expected SELECT, DELETE, SHOW, CREATE, DROP, GRANT, REVOKE, ALTER, SET at line 1, char 1"
}

References

1. influxdb_getting_started