一、安装saltstack

1)官网安装

http://repo.saltstack.com/#rhel

saltstack的模块:   https://www.unixhot.com/docs/saltstack/ref/modules/all/

2)启动服务

安装源,(所有机器)
yum install https://repo.saltstack.com/yum/redhat/salt-repo-latest.el7.noarch.rpm -y [root@k8s6 ~]# yum install salt-master salt-minion -y # 安装master和agent [root@node01 ~]# yum install salt-minion -y # 节点安装agent ---
直接启动master
[root@k8s6 ~]# systemctl start salt-master 在master修改salt-minion 配置文件
[root@k8s6 ~]# cd /etc/salt/
[root@k8s6 salt]# cp /etc/salt/minion /etc/salt/minion.bak
[root@k8s6 salt]# vim /etc/salt/minion
master: 192.168.10.22
[root@k8s6 salt]# systemctl start salt-minion # 启动agent
启动会产生 minion_id 这个文件,内容默认为主机名
[root@k8s6 salt]# cat minion_id
k8s6
---
节点服务器修改配置文件
[root@node01 salt]# vim /etc/salt/minion
master: 192.168.10.22
[root@node01 salt]# systemctl start salt-minion

3)秘钥认证过程

master和agent虽然都启动了,但需要得到master的认可才行
agent启动后会产生秘钥对
[root@node01 salt]# tree pki
pki
├── master
└── minion
├── minion.pem 私钥
└── minion.pub 公钥 服务端的秘钥对
[root@k8s6 salt]# tree pki
pki
├── master
│   ├── master.pem 私钥
│   ├── master.pub 公钥
│   ├── minions
│   ├── minions_autosign
│   ├── minions_denied
│   ├── minions_pre 查看正在等待被管理的机器
│   │   ├── k8s6
│   │   └── node01
│   └── minions_rejected
└── minion
├── minion.pem
└── minion.pub
[root@k8s6 salt]# salt-key # 列出所有的key
Accepted Keys:
Denied Keys:
Unaccepted Keys:
k8s6
node01
Rejected Keys:
[root@k8s6 salt]# salt-key -a k8s6 # 同意
The following keys are going to be accepted:
Unaccepted Keys:
k8s6
Proceed? [n/Y] y
Key for minion k8s6 accepted.
[root@k8s6 salt]# salt-key # 再次查看
Accepted Keys:
k8s6
Denied Keys:
Unaccepted Keys:
node01
Rejected Keys:
[root@k8s6 salt]# salt-key -a node* # 使用通配符
The following keys are going to be accepted:
Unaccepted Keys:
node01
Proceed? [n/Y] y
Key for minion node01 accepted. 再次查看文件 ===》认证过程则是交换公钥的过程
[root@k8s6 salt]# tree pki
pki
├── master
│   ├── master.pem
│   ├── master.pub
│   ├── minions
│   │   ├── k8s6
│   │   └── node01
│   ├── minions_autosign
│   ├── minions_denied
│   ├── minions_pre
│   └── minions_rejected
└── minion
├── minion_master.pub
├── minion.pem
└── minion.pub
[root@node01 salt]# tree pki
pki
├── master
└── minion
├── minion_master.pub
├── minion.pem
└── minion.pub

二、执行命令

1) 直接命令行执行命令

[root@k8s6 ~]# salt '*' test.ping    # 查看机器在不在
k8s6:
True
node01:
True
[root@k8s6 ~]# salt 'node01' test.ping
node01:
True
[root@k8s6 ~]# salt "node01" cmd.run "date" 执行命令
node01:
Mon Mar :: CST
[root@k8s6 ~]# salt "node01" cmd.run "w" 新命令
node01:
:: up days, :, user, load average: 0.00, 0.01, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/ 192.168.10.22 Thu19 3days .10s .10s -bash

2)以执行文本的形式去执行

2.1)修改配置服务

[root@k8s6 ~]# vim /etc/salt/master
#file_roots:
# base:
# - /srv/salt
===》改为
file_roots:
base:
- /srv/salt

vim /etc/salt/master

2.2)重启服务

[root@k8s6 ~]# systemctl restart salt-master
[root@k8s6 ~]# mkdir -p /srv/salt/web

2.3)编辑apache.sls文件,安装启动httpd服务

[root@k8s6 ~]# cat /srv/salt/web/apache.sls
apache-install:
pkg.installed:
- names:
- httpd
- httpd-devel apache-service:
service.running:
- name: httpd
- enable: True

apache.sls

2.4)执行过程

[root@k8s6 ~]# salt '*' state.sls web.apache

执行中,发生的事情。master将编辑的文件发生给minion

[root@node01 ~]# cd /var/cache/salt/
[root@node01 salt]# tree
.
└── minion
├── extmods
├── files
│   └── base
│   └── web
│   └── apache.sls
└── proc
└── directories, files

3)salt的高级状态,指定哪台机器执行什么服务。(top file使用案例一)

3.1)编辑配置文件,让k8s去执行web文件夹内的apache服务

[root@k8s6 ~]# cat /srv/salt/top.sls
base:
'k8s6':
- web.apache

3.2)执行之前需要 检测,防止出错

[root@k8s6 ~]# salt 'k8s6' state.highstate test=True      # 先检测
[root@k8s6 ~]# salt 'k8s6' state.highstate # 再执行

三、salt的消息队列

1)服务端监听的端口

消息的发布与订阅
[root@k8s6 ~]# netstat -lntup|grep python
tcp 0.0.0.0: 0.0.0.0:* LISTEN /python 4505端口,消息发布的监听端口
tcp 0.0.0.0: 0.0.0.0:* LISTEN /python
[root@k8s6 ~]# lsof -i: -n
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
salt-mini root 21u IPv4 0t0 TCP 192.168.10.22:->192.168.10.22: (ESTABLISHED)
salt-mast root 16u IPv4 0t0 TCP *: (LISTEN)
salt-mast root 18u IPv4 0t0 TCP 192.168.10.22:->192.168.10.23: (ESTABLISHED)
salt-mast root 19u IPv4 0t0 TCP 192.168.10.22:->192.168.10.22: (ESTABLISHED) 消息的返回值
[root@k8s6 ~]# lsof -i: -n
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
salt-mast root 24u IPv4 0t0 TCP *: (LISTEN)

2)安装服务yum install python-setproctitle -y 。可查看具体进程跑的服务

[root@k8s6 ~]# ps aux|grep salt-master
root 0.0 0.0 pts/ S+ : : grep --color=auto salt-master
root 0.0 1.0 ? Ss : : /usr/bin/python /usr/bin/salt-master
root 0.0 0.5 ? S : : /usr/bin/python /usr/bin/salt-master
root 0.0 0.9 ? Sl : : /usr/bin/python /usr/bin/salt-master
root 0.0 0.9 ? S : : /usr/bin/python /usr/bin/salt-master
root 0.2 1.8 ? S : : /usr/bin/python /usr/bin/salt-master
root 0.0 0.9 ? S : : /usr/bin/python /usr/bin/salt-master
root 0.0 0.9 ? Sl : : /usr/bin/python /usr/bin/salt-master
root 0.0 1.4 ? Sl : : /usr/bin/python /usr/bin/salt-master
root 0.2 0.9 ? Sl : : /usr/bin/python /usr/bin/salt-master
root 0.0 1.3 ? Sl : : /usr/bin/python /usr/bin/salt-master
root 0.0 1.4 ? Sl : : /usr/bin/python /usr/bin/salt-master
root 0.0 1.4 ? Sl : : /usr/bin/python /usr/bin/salt-master
root 0.0 1.4 ? Sl : : /usr/bin/python /usr/bin/salt-master
[root@k8s6 ~]# yum install python-setproctitle -y
[root@k8s6 ~]# systemctl restart salt-master
[root@k8s6 ~]# ps aux|grep salt-master
root 0.2 1.0 ? Ss : : /usr/bin/python /usr/bin/salt-master ProcessManager
root 0.0 0.5 ? S : : /usr/bin/python /usr/bin/salt-master MultiprocessingLoggingQueue
root 0.0 0.9 ? Sl : : /usr/bin/python /usr/bin/salt-master ZeroMQPubServerChannel
root 0.0 0.8 ? S : : /usr/bin/python /usr/bin/salt-master EventPublisher
root 0.3 1.2 ? S : : /usr/bin/python /usr/bin/salt-master Maintenance
root 0.0 0.9 ? S : : /usr/bin/python /usr/bin/salt-master ReqServer_ProcessManager
root 0.0 0.9 ? Sl : : /usr/bin/python /usr/bin/salt-master MWorkerQueue
root 0.7 1.2 ? Sl : : /usr/bin/python /usr/bin/salt-master MWorker-
root 0.7 1.2 ? Sl : : /usr/bin/python /usr/bin/salt-master MWorker-
root 0.7 1.2 ? Sl : : /usr/bin/python /usr/bin/salt-master MWorker-
root 0.1 0.9 ? Sl : : /usr/bin/python /usr/bin/salt-master FileserverUpdate
root 0.7 1.2 ? Sl : : /usr/bin/python /usr/bin/salt-master MWorker-
root 0.7 1.2 ? Sl : : /usr/bin/python /usr/bin/salt-master MWorker-
root 0.0 0.0 pts/ S+ : : grep --color=auto salt-master

yum install python-setproctitle -y

四、根据salt的组件角色来进行分组

1)根据内置组件判断分组执行服务器的命令

[root@k8s6 ~]# salt 'k8s6' grains.ls        显示所有的key
[root@k8s6 ~]# salt 'k8s6' grains.items 查看所有的key
[root@k8s6 ~]# salt 'k8s6' grains.item os 查看key里面的值,如操作系统
[root@k8s6 ~]# salt -G 'os:CentOS' test.ping 目标选择。根据操作系统来进行选择执行的命令
k8s6:
True
node01:
True
[root@k8s6 ~]# salt -G 'os:CentOS' cmd.run 'echo hehe'
k8s6:
hehe
node01:
hehe

2)自定义角色进行分组

[root@k8s6 ~]# vim /etc/salt/minion
#grains:
# roles:
# - webserver
# - memcache
===》
grains:
roles: apache
[root@k8s6 ~]# salt '*' grains.item roles
k8s6:
----------
roles:
node01:
----------
roles:
[root@k8s6 ~]#
[root@k8s6 ~]# systemctl restart salt-minion
[root@k8s6 ~]# salt '*' grains.item roles
k8s6:
----------
roles:
apache
node01:
----------
roles:

执行命令,找到 有apache服务的,为一个角色

[root@k8s6 ~]# netstat -lntup|grep httpd
tcp6 ::: :::* LISTEN /httpd
[root@k8s6 ~]# salt -G 'roles:apache' cmd.run 'systemctl stop httpd'
k8s6:
[root@k8s6 ~]# netstat -lntup|grep httpd
[root@k8s6 ~]# salt -G 'roles:apache' cmd.run 'systemctl start httpd'
k8s6:
[root@k8s6 ~]#

五、top案例使用方式二。根据角色来选择

1)配置文件编写,在服务端编写角色

[root@k8s6 ~]# cat /srv/salt/top.sls
base:
'k8s6':
- web.apache
'roles:apache':
- match: grain      选择匹配方式
- web.apache

2)在nodes编写角色

[root@node01 salt]# cat /etc/salt/grains
cloud: openstack

3)刷新出来角色(重启或刷新)

[root@node01 salt]# systemctl restart salt-minion
master服务端获取角色
[root@k8s6 ~]# salt '*' grains.item cloud
k8s6:
----------
cloud:
node01:
----------
cloud:
openstack
================
可以不用重启,可刷新后,再获取
[root@k8s6 ~]# salt '*' saltutil.sync_grains 服务端刷新

六、开发一个grains。使用Python自定义item

1)脚本存放的固定位置文件夹

mkdir /srv/salt/_grains

2)Python脚本返回字典即可

[root@k8s6 ~]# cat /srv/salt/_grains/my_grains.py
#!/usr/bin/env python
#-*- coding: utf- -*- def my_grains():
grains = {}
grains["iaas"] = "openstack"
grains["edu"] = "oldboy"
return grains

my_grains.py

3)执行脚本同步命令

[root@k8s6 ~]# salt '*' saltutil.sync_grains
k8s6:
- grains.my_grains
node01:
- grains.my_grains

salt '*' saltutil.sync_grains

同步之后可在node节点中查看到该python脚本

[root@node01 ~]# cd /var/cache/salt/
[root@node01 salt]# tree
.
└── minion
├── accumulator
├── extmods
│   └── grains
│   ├── my_grains.py
│   └── my_grains.pyc
├── files
│   └── base
│   ├── _grains
│   │   └── my_grains.py
│   ├── top.sls
│   └── web
│   └── apache.sls
├── highstate.cache.p
├── module_refresh
├── proc
└── sls.p

cd /var/cache/salt/

查看效果

[root@k8s6 ~]# salt '*' grains.item iaas
k8s6:
----------
iaas:
openstack
node01:
----------
iaas:
openstack

4)grians的优先级查找

Grians优先级
)系统自带
)grains 文件写的
)minion 配置文件写的
)自己写的

七、另一种动态配置管理pillar

1)启动配置管理

[root@k8s6 ~]# salt "*" pillar.items    # 先查看,没有内容
k8s6:
----------
node01:
----------
[root@k8s6 ~]# vim /etc/salt/master # 修改配置
#pillar_opts: False
==》pillar_opts: True
[root@k8s6 ~]# systemctl restart salt-master
[root@k8s6 ~]# salt "*" pillar.items # 再次查看,将出现很多值

salt "*" pillar.items

展示的内容太多,不太好使用,还是需要注释掉

2)使用过程

[root@k8s6 web]# cat /srv/pillar/web/apache.sls
{% if grains['os'] == 'CentOS' %}
apache: httpd
{% elif grains['os'] == 'Debian' %}
apache: apache2
{% endif %}
[root@k8s6 srv]# cat /srv/pillar/top.sls
base:
'k8s6':
- web.apache
[root@k8s6 srv]# tree pillar/
pillar/
├── top.sls
└── web
└── apache.sls
[root@k8s6 ~]# salt '*' pillar.items apache
k8s6:
----------
apache:
node01:
----------
apache:
[root@k8s6 ~]#
[root@k8s6 ~]# salt '*' saltutil.refresh_pillar # 刷新
k8s6:
True
node01:
True
[root@k8s6 ~]# salt '*' pillar.items apache
k8s6:
----------
apache:
httpd
node01:
----------
apache:
[root@k8s6 ~]# salt -I 'apache:httpd' test.ping # 匹配到执行命令??

salt '*' pillar.items apache

3)Grians和pillar的区别

Grians vs Pillar
类型 数据采集方式 应用场景 定义位置
Grians 静态 minion启动时收集 数据查询,目标选择,配置管理 minion
Pillar 动态 master自定义 目标选择,配置管理,敏感数据 master

八、执行命令解析

1)选择目标机器的通配符

选择目标机器的通配符
salt '*' test.ping
salt 'web01' test.ping
salt 'web0[1|2]' test.ping
salt 'web?.com' test.ping
salt 'web0[1-2]' test.ping
salt 'web0[!2]' test.ping
salt -L 'web01,web02' test.ping
salt -E 'web(01|02)' test.ping
salt -S 192.168.10.22 test.ping
salt -S 192.168.10.0/ test.ping
salt -G 'os:RedHat' --batch-size % apache.singel restart # --batch-size %,根据25%的比例重启服务

2)自定义分组

[root@k8s6 ~]# vim /etc/salt/master
#nodegroups:
# group1: 'L@foo.domain.com,bar.domain.com,baz.domain.com or bl*.domain.com'
# group2: 'G@os:Debian and foo.domain.com'
# group3: 'G@os:Debian and N@group1'
# group4:
# - 'G@foo:bar'
# - 'or'
# - 'G@foo:baz'
nodegroups: # 新增
web: 'L@k8s6,node01' # 分组的。新增 [root@k8s6 ~]# systemctl restart salt-master
[root@k8s6 ~]# salt -N web test.ping

3)模块解析执行命令

salt '*' network.active_tcp        # 返回所有的tcp连接
salt '*' network.arp # 返回arp表
salt '*' network.get_hostname # 返回主机名
salt '*' service.available sshd # 查看服务是否在运行
salt '*' service.get_all # 查看所有正在运行的服务
salt '*' service.status sshd # 查看运行的状态
salt-cp '*' /etc/hosts /tmp/hehe # 拷贝文件
salt '*' state.show_top # 查看在top里面需要做什么事
salt '*' state.single pkg.installed name=lsof # 手动执行安装
= salt '*' cmd.run 'yum install lsof -y'

九、将返回结果写入数据库

https://www.unixhot.com/docs/saltstack/ref/returners/index.html        # 支持的返回的位置
salt '*' state.single pkg.installed name=MySQL-python  # 实质则是安装mysql
https://www.unixhot.com/docs/saltstack/ref/returners/all/salt.returners.mysql.html  # 官网,所需要执行的步骤

1)数据库操作,创建库,授权

)创建salt数据库
CREATE DATABASE `salt`
DEFAULT CHARACTER SET utf8
DEFAULT COLLATE utf8_general_ci; )进入当前库
USE `salt`; )创建jids表
DROP TABLE IF EXISTS `jids`;
CREATE TABLE `jids` (
`jid` varchar() NOT NULL,
`load` mediumtext NOT NULL,
UNIQUE KEY `jid` (`jid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE INDEX jid ON jids(jid) USING BTREE; )创建salt_returns表
DROP TABLE IF EXISTS `salt_returns`;
CREATE TABLE `salt_returns` (
`fun` varchar() NOT NULL,
`jid` varchar() NOT NULL,
`return` mediumtext NOT NULL,
`id` varchar() NOT NULL,
`success` varchar() NOT NULL,
`full_ret` mediumtext NOT NULL,
`alter_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
KEY `id` (`id`),
KEY `jid` (`jid`),
KEY `fun` (`fun`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; )创建salt_events表
DROP TABLE IF EXISTS `salt_events`;
CREATE TABLE `salt_events` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`tag` varchar() NOT NULL,
`data` mediumtext NOT NULL,
`alter_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`master_id` varchar() NOT NULL,
PRIMARY KEY (`id`),
KEY `tag` (`tag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; )授权
grant all on salt.* to salt@'%' indentified by 'salt@pw';
flush privileges; 测试连接
mysql -h192.168.10. -usalt -psalt@pw

2)修改配置文件,添加数据库的连接方式

[root@k8s6 ~]# vim /etc/salt/minion
# 最后添加
mysql.host: '192.168.10.22'
mysql.user: 'salt'
mysql.pass: 'salt@pw'
mysql.db: 'salt'
mysql.port:
[root@k8s6 ~]# systemctl restart salt-minion

vim /etc/salt/minion

3)执行操作

[root@k8s6 ~]# systemctl restart salt-minion
[root@k8s6 ~]# tail -f /var/log/salt/minion 进行日志监听
[root@k8s6 ~]# salt '*' test.ping --return mysql
进入数据库查看是否有数据

十、编写自己的执行模块

存放位置: /srv/salt/_modules
命名:文件名就是模块名
[root@k8s6 ~]# cat /srv/salt/_modules/my_disk.py
def list():
cmd = "df -h"
ret = __salt__["cmd.run"](cmd)
return ret
[root@k8s6 ~]# salt '*' saltutil.sync_modules 刷新
k8s6:
- modules.my_disk
node01:
- modules.my_disk
[root@k8s6 ~]# salt '*' my_disk.list # 执行自己的模块

saltstack基本操作第一篇章的更多相关文章

  1. saltstack系列~第一篇

    一 简介:从今天开始学习saltstack 二 salt的认证系列操作 1 原理 saltstack通过/etc/salt/pki/目录下面的配置文件的密钥进行通信,master端接受minion端后 ...

  2. 《JavaScript高级程序设计》心得笔记-----第一篇章

    第一章 JavaScript由ECMAScript.DOM.BOM组成.其中BOM功能在HTML5中有了正式的规范,使BOM的兼容性越来越高. 第二章 1.<script>属性中的asyn ...

  3. 【第一篇章-android平台buffer播放探索】native media

    在android平台,从4.0开始,提出了openmax架构,所以在DNK的R7版本中有了openmax AL层播放的DEMO即native media,这个DEMO就是读本地文件,然后把所读buff ...

  4. C语言学习之路,第一篇章。

    看的书是 C  primer plus  ,这本书好评很多, 学过C#,没有精通,了解Java,所以看这本书会很容易上手,编译器用的是VC++6.0,因为VS2010好像不支持C99标准,有些代码功能 ...

  5. saltstack 基本操作

    一.常用操作 ①.模块查看 #查看全部模块 [root@k8s_master ~]# salt '*' sys.list_modules # "*"为所有node节点 (此处可以写 ...

  6. MySQL的基本操作--第一弹

    前言:在听许嵩,忆当年,意气风发 ———————————————————————————————————————————————— 好了,今天和大家同步讲解mysql的知识了.都是最基本的知识. 一. ...

  7. Redis第一篇章 Hello Word!

    1.找到redis目录 2.在新建一个文件夹(myredis) 3.将redis.conf 进行复制到myredis 文件夹里面 4.启动redis redis-server /home/dc2-us ...

  8. 12 Spring Data JPA:orm思想和hibernate以及jpa的概述和jpa的基本操作

    spring data jpa day1:orm思想和hibernate以及jpa的概述和jpa的基本操作 day2:springdatajpa的运行原理以及基本操作 day3:多表操作,复杂查询 d ...

  9. 01 . SaltStack部署配置及简单应用

    SaltStack简介 SaltStack saltstack是一个新的基础平台管理工具,只需要花费数分钟即可运行起来,可以支撑管理上万台服务器的规模,数秒钟即可完成数据传递. saltstack是使 ...

随机推荐

  1. tensorflow实现一个神经网络简单CNN网络

    本例子用到了minst数据库,通过训练CNN网络,实现手写数字的预测. 首先先把数据集读取到程序中(MNIST数据集大约12MB,如果没在文件夹中找到就会自动下载): mnist = input_da ...

  2. 云中沙箱学习笔记1-快速部署并使用MySQL数据库

    1.1 背景知识 业务背景 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于Oracle旗下产品.MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面MyS ...

  3. 2018-2-13-C#-复制列表

    title author date CreateTime categories C# 复制列表 lindexi 2018-2-13 17:23:3 +0800 2018-2-13 17:23:3 +0 ...

  4. python浮点数与整数间的转化

    舍弃小数部分 >>> math.trunc(12.533222) 12 >>> round(12.2544) 12 按给定小数位数四舍五入 >>> ...

  5. MySQL01---简介及安装

    目录 MySQL简介及安装 DBA工作内容 DBA的职业素养 MySQL简介及安装 01 什么是数据? 02 什么是数据库管理系统 03 数据库管理系统种类 关系型数据库(RDMS)与非关系型数据库( ...

  6. Linux之scp命令的使用

    Linux之scp命令的使用 1. scp简介 1.1 命令功能: scp是 secure copy的缩写, scp是linux系统下基于ssh登陆进行安全的远程文件拷贝命令.linux的scp命令可 ...

  7. 牛客小白月赛16 F 小石的妹子 (线段树)

    链接:https://ac.nowcoder.com/acm/contest/949/F来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言52428 ...

  8. Wait and Click Element

    Wait and Click Element [Documentation] 等待元素出现并单击元素 [Arguments] ${locator} Wait Until Element Is Visi ...

  9. 牛客网NOIP赛前集训营-提高组(第六场)A-最长路

    题目描述 有一张 n 个点 m 条边的有向图,每条边上都带有一个字符,字符用一个数字表示. 求以每个点为起点的最长路,输出走过的边的字符构成的字符串的字典序最小的方案. 为了方便,你需要这样输出方案: ...

  10. webRTC脱坑笔记(二)— webRTC API之MediaStream(getUserMedia)

    webRTC API WebRTC API包括媒体捕获.音频视频的编码和解码.传输层和会话管理. getUserMedia():捕获音频和视频. MediaRecorder:录制音频和视频. RTCP ...