在本章中,我们将探索一种被成千上万的网络和系统工程师使用的流行自动化框架Ansible,Ansible用于管理服务器和网络设备,通过多种传输协议如SSH、Netconf和API来提供可靠的基础设施。
我们首先将学习ansible中使用的术语,如何构建包含基础设施访问详细信息的清单文件,使用条件、循环和模板渲染等功能构建强大的Ansibleplaybook。
Ansible属于软件配置管理类别;它用于管理多个不同设备和服务器上的配置生命周期,确保所有设备上都应用相同的步骤,并帮助创建基础设施即代码(IaaC)环境。
本章将涵盖以下主题:
Ansible是一个自动化工具和完整的框架,它提供了基于Python工具的抽象层。最初,它是设计用来处理任务自动化的。这个任务可以在单个服务器上执行,也可以在成千上万的服务器上执行,ansible都可以毫无问题地处理;后来,Ansible的范围扩展到了网络设备和云提供商。Ansible遵循“幂等性”的概念,其中Ansible指令可以多次运行相同的任务,并始终在所有设备上给出相同的配置,最终达到期望的状态,变化最小。例如,如果我们运行Ansible将文件上传到特定组的服务器,然后再次运行它,Ansible将首先验证文件是否已经存在于远程目的地,如果存在,那么ansible就不会再次上传它。
再次。这个功能叫做“幂等性”。
Ansible的另一个方面是它是无代理的。在运行任务之前,Ansible不需要在服务器上安装任何代理。它利用SSH连接和Python标准库在远程服务器上执行任务,并将输出返回给Ansible服务器。此外,它不会创建数据库来存储远程机器信息,而是依赖于一个名为inventory的平面文本文件来存储所有所需的服务器信息,如IP地址、凭据和基础设施分类。以下是一个简单清单文件的示例:
[all:children]web-serversdb-servers[web-servers]web01Ansible_ssh_host=192.168.10.10[db-servers]db01Ansible_ssh_host=192.168.10.11db02Ansible_ssh_host=192.168.10.12[all:vars]Ansible_ssh_user=rootAnsible_ssh_pass=access123[db-servers:vars]Ansible_ssh_user=rootAnsible_ssh_pass=access123[local]127.0.0.1Ansible_connection=localAnsible_python_interpreter="/usr/bin/python"请注意,我们将在我们的基础设施中执行相同功能的服务器分组在一起(比如数据库服务器,在一个名为[db-servers]的组中;同样的,对于[web-servers]也是如此)。然后,我们定义一个特殊的组,称为[all],它结合了这两个组,以防我们有一个针对所有服务器的任务。
children关键字在[all:children]中的意思是组内的条目也是包含主机的组。
Ansible的“临时”模式允许用户直接从终端向远程服务器执行任务。假设您想要在特定类型的服务器上更新特定的软件包,比如数据库或Web后端服务器,以解决一个新的bug。与此同时,您不想要开发一个复杂的playbook来执行一个简单的任务。通过利用Ansible的临时模式,您可以在Ansible主机终端上输入命令来在远程服务器上执行任何命令。甚至一些模块也可以在终端上执行;我们将在“在临时模式下使用Ansible”部分中看到这一点。
Ansible软件包在所有主要的Linux发行版上都可用。在本节中,我们将在Ubuntu和CentOS机器上安装它。在编写本书时使用的是Ansible2.5版本,并且它支持Python2.6和Python2.7。此外,从2.2版本开始,Ansible为Python3.5+提供了技术预览。
在安装Ansible之前,您需要安装和启用EPEL存储库。要这样做,请使用以下命令:
sudoyuminstallepel-release然后,按照以下命令安装Ansible软件包:
sudoyuminstallAnsibleUbuntu首先确保您的系统是最新的,并添加Ansible通道。最后,安装Ansible软件包本身,如下面的代码片段所示:
您可以通过运行Ansible--version来验证您的安装,以检查已安装的版本:
当您需要在远程机器上执行简单操作而不创建复杂和持久的任务时,可以使用Ansible临时模式。这通常是用户在开始使用Ansible时首先使用的地方,然后再执行playbook中的高级任务。
执行临时命令需要两件事。首先,您需要清单文件中的主机或组;其次,您需要要执行的针对目标机器的Ansible模块:
[all:children]centos-serversubuntu-servers[centos-servers]centos-machine01Ansible_ssh_host=10.10.10.193[ubuntu-servers]ubuntu-machine01Ansible_ssh_host=10.10.10.140[all:vars]Ansible_ssh_user=rootAnsible_ssh_pass=access123[centos-servers:vars]Ansible_ssh_user=rootAnsible_ssh_pass=access123[ubuntu-servers:vars]Ansible_ssh_user=rootAnsible_ssh_pass=access123[routers]gatewayansible_ssh_host=10.10.88.110ansible_ssh_user=ciscoansible_ssh_pass=cisco[local]127.0.0.1Ansible_connection=localAnsible_python_interpreter="/usr/bin/python"#Ansible-ihostsall-mping-i参数将接受我们添加的清单文件,而-m参数将指定Ansible模块的名称。
运行命令后,您将得到以下输出,指示连接到远程机器失败:
ubuntu-machine01|FAILED!=>{"msg":"UsingaSSHpasswordinsteadofakeyisnotpossiblebecauseHostKeycheckingisenabledandsshpassdoesnotsupportthis.Pleaseaddthishost'sfingerprinttoyourknown_hostsfiletomanagethishost."}centos-machine01|FAILED!=>{"msg":"UsingaSSHpasswordinsteadofakeyisnotpossiblebecauseHostKeycheckingisenabledandsshpassdoesnotsupportthis.Pleaseaddthishost'sfingerprinttoyourknown_hostsfiletomanagethishost."}这是因为远程机器不在Ansible服务器的known_hosts中;可以通过两种方法解决。
第一种方法是手动SSH到它们,这将将主机指纹添加到服务器。或者,您可以在Ansible配置中完全禁用主机密钥检查,如下面的代码片段所示:
sed-i-e's/#host_key_checking=False/host_key_checking=False/g'/etc/Ansible/Ansible.cfgsed-i-e's/#StrictHostKeyCheckingask/StrictHostKeyCheckingno/g'/etc/ssh/ssh_config重新运行Ansible命令,您应该从三台机器中获得成功的输出:
另一个有用的模块是apt或yum,用于管理Ubuntu或CentOS服务器上的软件包。以下示例将在Ubuntu机器上安装apache2软件包:
#Ansible-ihostsubuntu-servers-mapt-a"name=apache2state=present"apt模块中的状态可以有以下值:
您可以通过运行Ansible-doc
service模块用于管理服务的操作和当前状态。您可以在state选项中将服务状态更改为started、restarted或stopped,ansible将运行适当的命令来更改状态。同时,您可以通过配置enabled来配置服务是否在启动时启用或禁用。
#Ansible-ihostscentos-servers-mservice-a"name=mariadbstate=restarted"以adhoc模式运行Ansible的另一种方法是直接将命令传递给Ansible,而不是使用内置模块,而是使用-a参数:
#Ansible-ihostsall-a"ifconfig"您甚至可以通过运行reboot命令重新启动服务器;但这次,我们只会针对CentOS服务器运行它:
#Ansible-ihostscentos-servers-a"reboot"有时,您需要使用不同的用户运行命令(或模块)。当您在具有分配给不同于SSH用户的特定权限的远程服务器上运行脚本时,这将非常有用。在这种情况下,我们将添加-u,--become和--ask-become-pass(-K)开关。这将使Ansible使用提供的用户名运行命令,并提示您输入用户的密码:
#Ansible-ihostsubuntu-servers--become-userbassim--ask-become-pass-a"cat/etc/sudoers"Ansible的实际工作方式Ansible基本上是用Python编写的,但它使用自己的DSL(领域特定语言)。您可以使用此DSL编写,ansible将在远程机器上将其转换为Python以执行任务。因此,它首先验证任务语法并从Ansible主机复制模块到远程服务器,然后在远程服务器上执行它。
执行的结果以json格式返回到Ansible主机,因此您可以通过了解其键来匹配任何返回的值:
在安装了Python的网络设备的情况下,Ansible使用API或netconf(如果网络设备支持,例如Juniper和CiscoNexus);或者,它只是使用paramiko的exec_command()函数执行命令,并将输出返回到Ansible主机。这可以通过使用raw模块来完成,如下面的代码片段所示:
#Ansible-ihostsrouters-mraw-a"showarp"gateway|SUCCESS|rc=0>>SatApr2101:33:58.391CAIROAddressAgeHardwareAddrStateTypeInterface85.54.41.9-45ea.2258.d0a9InterfaceARPATenGigE0/2/0/010.88.18.1-d0b7.428b.2814SatelliteARPATenGigE0/2/0/0192.168.100.1-00a7.5a3b.4193InterfaceARPAGigabitEthernet100/0/0/9192.168.100.202:08:03fc5b.3937.0b00DynamicARPA\创建您的第一个剧本现在魔术派对可以开始了。Ansible剧本是一组需要按顺序执行的命令(称为任务),它描述了执行完成后主机的期望状态。将剧本视为包含一组指令的手册,用于更改基础设施的状态;每个指令都依赖于许多内置的Ansible模块来执行任务。例如,您可能有一个用于构建Web应用程序的剧本,其中包括SQL服务器,用作后端数据库和nginxWeb服务器。剧本将有一系列任务针对每组服务器执行,以将它们的状态从不存在更改为存在,或者更改为重新启动或不存在,如果要删除Web应用程序。
剧本的强大之处在于您可以使用它在任何地方配置和设置基础设施。用于创建开发环境的相同过程将用于生产环境。剧本用于创建在您的基础设施上运行的自动化工作流程:
剧本是用YAML编写的,我们在第六章中讨论过,使用Python和Jinja2生成配置。剧本由多个play组成,针对清单文件中定义的一组主机执行。主机将被转换为Pythonlist,列表中的每个项目将被称为play。在前面的示例中,db-servers任务是一些play,并且仅针对db-servers执行。在剧本执行期间,您可以决定运行文件中的所有play,仅特定play或具有特定标记的任务,而不管它们属于哪个play。
现在,让我们看看我们的第一个剧本,以了解其外观和感觉:
-hosts:centos-serversremote_user:roottasks:-name:Installopensshyum:pkg=openssh-serverstate=installed-name:Starttheopensshservice:name=sshdstate=startedenabled=yes这是一个简单的剧本,有一个包含两个任务的play:
现在,我们需要将其应用于特定主机(或一组主机)。因此,我们将hosts设置为之前在inventory文件中定义的CentOS-servers,并且我们还将remote_user设置为root,以确保之后的任务将以root权限执行。
任务将包括名称和Ansible模块。名称用于描述任务。为任务提供名称并不是强制性的,但建议这样做,以防需要从特定任务开始执行。
第二部分是Ansible模块,这是必需的。在我们的示例中,我们使用了核心模块yum来在目标服务器上安装openssh-server软件包。第二个任务具有相同的结构,但这次我们将使用另一个核心模块,称为service,来启动和启用sshd守护程序。
最后要注意Ansible中不同组件的缩进。例如,任务的名称应该在同一级别,而tasks应该与同一行上的hosts对齐。
让我们在我们的自动化服务器上运行playbook并检查输出:
#Ansible-playbook-ihostsfirst_playbook.yamlPLAY[centos-servers]**********************************************************************TASK[GatheringFacts]*********************************************************************ok:[centos-machine01]TASK[Installopenssh]*********************************************************************ok:[centos-machine01]TASK[Starttheopenssh]*******************************************************************ok:[centos-machine01]PLAYRECAP*********************************************************************************centos-machine01:ok=3changed=0unreachable=0failed=0您可以看到playbook在centos-machine01上执行,并且任务按照playbook中定义的顺序依次执行。
在本章的这一部分,我们将看一些Ansibleplaybook中的高级功能。
Ansibleplaybook可以根据任务内部特定条件的结果执行任务(或跳过任务)——例如,当您想要在特定操作系统家族(Debian或CentOS)上安装软件包时,或者当操作系统是特定版本时,甚至当远程主机是虚拟机而不是裸机时。这可以通过在任务内部使用when子句来实现。
让我们增强先前的playbook,并将openssh-server安装限制为仅适用于基于CentOS的系统,这样当它遇到使用apt模块而不是yum的Ubuntu服务器时,就不会出错。
首先,我们将在我们的inventory文件中添加以下两个部分,将CentOS和Ubuntu机器分组到infra部分中:
[infra:children]centos-serversubuntu-servers[infra:vars]Ansible_ssh_user=rootAnsible_ssh_pass=access123然后,我们将重新设计playbook中的任务,添加when子句,将任务执行限制为仅适用于基于CentOS的机器。这应该读作如果远程机器是基于CentOS的,那么我将执行任务;否则,跳过。
-hosts:infraremote_user:roottasks:-name:Installopensshyum:pkg=openssh-serverstate=installedwhen:Ansible_distribution=="CentOS"-name:Starttheopensshservice:name=sshdstate=startedenabled=yeswhen:Ansible_distribution=="CentOS"让我们运行playbook:
#Ansible-playbook-ihostsusing_when.yamlPLAY[infra]*******************************************************************************TASK[GatheringFacts]*********************************************************************ok:[centos-machine01]ok:[ubuntu-machine01]TASK[Installopenssh]*********************************************************************skipping:[ubuntu-machine01]ok:[centos-machine01]TASK[Starttheopenssh]*******************************************************************skipping:[ubuntu-machine01]ok:[centos-machine01]PLAYRECAP*********************************************************************************centos-machine01:ok=3changed=0unreachable=0failed=0ubuntu-machine01:ok=1changed=0unreachable=0failed=0请注意,playbook首先收集有关远程机器的信息(我们将在本章后面讨论),然后检查操作系统。当它遇到ubuntu-machine01时,任务将被跳过,并且在CentOS上将正常运行。
您还可以有多个条件需要满足才能运行任务。例如,您可以有以下playbook,验证两件事情——首先,机器基于Debian,其次,它是一个虚拟机,而不是裸机:
-hosts:infraremote_user:roottasks:-name:Installopensshapt:pkg=open-vm-toolsstate=installedwhen:-Ansible_distribution=="Debian"-Ansible_system_vendor=="VMware,Inc."运行此playbook将产生以下输出:
#Ansible-playbook-ihostsusing_when_1.yamlPLAY[infra]*******************************************************************************TASK[GatheringFacts]*********************************************************************ok:[centos-machine01]ok:[ubuntu-machine01]TASK[Installopenssh]*********************************************************************skipping:[centos-machine01]ok:[ubuntu-machine01]PLAYRECAP*********************************************************************************centos-machine01:ok=1changed=0unreachable=0failed=0ubuntu-machine01:ok=2changed=0unreachable=0failed=0Ansible的when子句还接受表达式。例如,您可以检查返回的输出中是否存在特定关键字(使用注册标志保存),并根据此执行任务。
以下playbook将验证OSPF邻居状态。第一个任务将在路由器上执行showipospfneighbor并将输出注册到名为neighbors的变量中。接下来的任务将检查返回的输出中是否有EXSTART或EXCHANGE,如果找到,将在控制台上打印一条消息:
Ansible提供了许多重复在play中执行相同任务的方法,但每次都有不同的值。例如,当您想在服务器上安装多个软件包时,您不需要为每个软件包创建一个任务。相反,您可以创建一个任务,安装一个软件包并向任务提供软件包名称的列表,Ansible将对它们进行迭代,直到完成安装。为此,我们需要在包含列表的任务内使用with_items标志,并使用变量{{item}},它作为列表中项目的占位符。playbook将利用with_items标志对一组软件包进行迭代,并将它们提供给yum模块,该模块需要软件包的名称和状态:
playbook的输出如下:
好的;您已经在系统中安装和删除了一系列软件包。您已经将文件复制到/从服务器。并且您已经通过使用Ansibleplaybook在服务器上做了很多改变。现在,您需要重新启动一些其他服务,或者向文件中添加一些行,以完成服务的配置。所以,您应该添加一个新的任务,对吗?是的,这是正确的。然而,Ansible提供了另一个很棒的选项,称为handlers,它不会在触发时自动执行(不像任务),而是只有在被调用时才会执行。这为您提供了灵活性,可以在play中的任务执行时调用它们。
处理程序与主机和任务具有相同的对齐方式,并位于每个play的底部。当您需要调用处理程序时,您可以在原始任务内使用notify标志,以确定将执行哪个处理程序;Ansible将它们链接在一起。
让我们看一个例子。我们将编写一个playbook,在CentOS服务器上安装和配置KVM。KVM在安装后需要进行一些更改,比如加载sysctl,启用kvm和802.1q模块,并在boot时加载kvm:
-hosts:centos-serversremote_user:roottasks:-name:"InstallKVM"yum:name={{item.name}}state={{item.state}}with_items:-{name:qemu-kvm,state:installed}-{name:libvirt,state:installed}-{name:virt-install,state:installed}-{name:bridge-utils,state:installed}notify:-loadsysctl-loadkvmatboot-enablekvmhandlers:-name:loadsysctlcommand:sysctl-p-name:enablekvmcommand:"{{item.name}}"with_items:-{name:modprobe-akvm}-{name:modprobe8021q}-{name:udevadmtrigger}-name:loadkvmatbootlineinfile:dest=/etc/modulesstate=presentcreate=Trueline={{item.name}}with_items:-{name:kvm}注意安装任务后使用notify。当任务运行时,它将按顺序通知三个处理程序,以便它们将被执行。处理程序将在任务成功执行后运行。这意味着如果任务未能运行(例如,找不到kvm软件包,或者没有互联网连接来下载它),则系统不会发生任何更改,kvm也不会被启用。
处理程序的另一个很棒的特性是,它只在任务中有更改时才运行。例如,如果您重新运行任务,Ansible不会安装kvm软件包,因为它已经安装;它不会调用任何处理程序,因为它在系统中没有检测到任何更改。
我们将在最后关于两个模块添加一个注释:lineinfile和command。第一个模块实际上是通过使用正则表达式向配置文件中插入或删除行;我们使用它来将kvm插入/etc/modules,以便在机器启动时自动启动KVM。第二个模块command用于在设备上直接执行shell命令并将输出返回给Ansible主机。
收集到的事实可以在后续的playbook中使用,设计任务条件。例如,我们使用when子句将openssh安装限制为仅适用于基于CentOS的系统:
when:Ansible_distribution=="CentOS"您可以通过在与主机和任务相同级别上配置gather_facts来在Ansibleplays中启用/禁用事实收集。
-hosts:centos-serversgather_facts:yestasks:
您可以使用点表示法或方括号从事实中获取特定值。例如,要获取eth0的IPv4地址,可以使用Ansible_eth0["ipv4"]["address"]或Ansible_eth0.ipv4.address。
与Ansible一起工作的最后一部分是了解它如何处理模板。Ansible使用我们在第六章中讨论过的Jinja2模板,使用Python和Jinja2生成配置。它使用Ansible事实或在vars部分提供的静态值填充参数,甚至使用使用register标志存储的任务的结果。
在以下示例中,我们将构建一个Ansibleplaybook,其中包含前面三个案例。首先,在vars部分中定义一个名为Header的变量,其中包含一个欢迎消息作为静态值。然后,我们启用gather_facts标志,以从目标机器获取所有可能的信息。最后,我们执行date命令,以获取服务器的当前日期并将输出存储在date_now变量中:
index.j2的内容如下。它将是一个简单的HTML页面,利用jinja2语言生成最终的HTML页面:
DateNowis:{{date_now.stdout}}
- IPv4Address:{{Ansible_default_ipv4['address']}}
- IPv4gateway:{{Ansible_default_ipv4['gateway']}}
- Hostname:{{Ansible_hostname}}
- TotalMemory:{{Ansible_memtotal_mb}}
- OperatingSystemFamily:{{Ansible_os_family}}
- SystemVendor:{{Ansible_system_vendor}}
Ansible是一个非常强大的工具,用于自动化IT基础设施。它包含许多模块和库,几乎涵盖了系统和网络自动化中的所有内容,使软件部署、软件包管理和配置管理变得非常容易。虽然Ansible可以在adhoc模式下执行单个模块,但Ansible的真正力量在于编写和开发playbook。
在本章中,我们将在CiscoUCS服务器上安装VMwareESXi5.5,并托管一些虚拟机。我们需要在ESXi服务器中启用一些功能,以便将一些外部端口暴露给外部世界:
将打开一个弹出窗口,其中包含服务、状态和各种可以应用的选项:
再次为ESXiShell服务重复相同的步骤。这将确保一旦ESXi服务器启动,两个服务都将启动,并且将打开并准备好接受连接。您可以测试两个服务,通过SSH连接到ESXiIP地址,并提供root凭据:
虚拟机(有时称为客户机)的基本单元是VMX文件。该文件包含构建虚拟机所需的所有设置,包括计算资源、分配的内存、硬盘和网络。此外,它定义了在机器上运行的操作系统,因此VMware可以安装一些工具来管理VM的电源。
还需要一个额外的文件:VMDK。该文件存储VM的实际内容,并充当VM分区的硬盘:
这些文件(VMX和VMDK)应存储在ESXiShell中的/vmfs/volumes/datastore1目录下,并且应该位于以虚拟机名称命名的目录中。
现在我们将创建模板文件,用于在Python中构建虚拟机。以下是我们需要使用Python和Jinja2生成的最终运行的VMX文件的示例:
.encoding="UTF-8"vhv.enable="TRUE"config.version="8"virtualHW.version="8"vmci0.present="TRUE"hpet0.present="TRUE"displayName="test_jinja2"#SpecsmemSize="4096"numvcpus="1"cpuid.coresPerSocket="1"#HDDscsi0.present="TRUE"scsi0.virtualDev="lsilogic"scsi0:0.deviceType="scsi-hardDisk"scsi0:0.fileName="test_jinja2.vmdk"scsi0:0.present="TRUE"#Floppyfloppy0.present="false"#CDRomide1:0.present="TRUE"ide1:0.deviceType="cdrom-image"ide1:0.fileName="/vmfs/volumes/datastore1/ISORoom/CentOS-7-x86_64-Minimal-1708.iso"#Networkingethernet0.virtualDev="e1000"ethernet0.networkName="network1"ethernet0.addressType="generated"ethernet0.present="TRUE"#VMTypeguestOS="ubuntu-64"#VMwareToolstoolScripts.afterPowerOn="TRUE"toolScripts.afterResume="TRUE"toolScripts.beforeSuspend="TRUE"toolScripts.beforePowerOff="TRUE"tools.remindInstall="TRUE"tools.syncTime="FALSE"我在文件中添加了一些注释,以说明每个块的功能。但是,在实际文件中,您看不到这些注释。
让我们分析文件并理解一些字段的含义:
现在我们将构建Jinja2模板;您可以查看第六章,使用Python和Jinja2进行配置生成,了解使用Jinja2语言进行模板化的基础知识:
Python有一些出色的库,可以处理Excel表中的数据。在第四章中,我们已经使用了Excel表,使用Python管理网络设备,当我们需要自动化netmiko配置并读取描述Excel文件基础设施的数据时。现在,我们将开始在自动化服务器中安装Pythonxlrd库。
使用以下命令安装xlrd:
按照以下步骤进行:
请注意,nrows和ncols是特殊变量,一旦打开计算工作表中的行数和列数的工作表,它们将被填充。您可以使用for循环进行迭代。编号始终从开始。
回到虚拟机示例。在Excel表中,我们将有以下数据,反映虚拟机设置:
为了将数据读入Python,我们将使用以下脚本:
importxlrdworkbook=xlrd.open_workbook(r"/media/bassim/DATA/GoogleDrive/Packt/EnterpriseAutomationProject/Chapter14_Creating_and_managing_VMware_virtual_machines/vm_inventory.xlsx")sheet=workbook.sheet_by_index(0)print(sheet.nrows)print(sheet.ncols)print(int(sheet.row(1)[1].value))forrowinrange(1,sheet.nrows):vm_name=sheet.row(row)[0].valuevm_memory_size=int(sheet.row(row)[1].value)vm_cpu=int(sheet.row(row)[2].value)cpu_per_socket=int(sheet.row(row)[3].value)vm_hdd_size=int(sheet.row(row)[4].value)vm_guest_os=sheet.row(row)[5].valuevm_network1=sheet.row(row)[6].value在前面的脚本中,我们做了以下事情:
最后一部分是从Jinja2模板生成VMX文件。我们将从Excel表中读取数据,并将其添加到空字典vmx_data中。稍后将该字典传递给Jinja2模板中的render()函数。Python字典键将是模板变量名,而值将是应该在文件中替换的值。脚本的最后一部分是在vmx_files目录中以写入模式打开文件,并为每个VMX文件写入数据:
文件存储在vmx_files下,每个文件都包含在Excel表中配置的虚拟机的特定信息:
现在,我们将使用paramiko和scp库连接到ESXiShell,并将这些文件上传到/vmfs/volumes/datastore1下。为了实现这一点,我们将首先创建一个名为upload_and_create_directory()的函数,该函数接受vmname、harddisksize和VMXsourcefile。paramiko将连接到ESXi服务器并执行所需的命令,这将在/vmfs/volumes/datastore1下创建目录和VMDK。最后,我们将使用scp模块中的SCPClient将源文件上传到先前创建的目录,并运行注册命令将机器添加到vSphere客户端:
最终代码应该如下所示:
如果在运行脚本后检查vSphere客户端,您会发现已经创建了四台机器,这些机器的名称是在Excel表中提供的:
此外,您会发现虚拟机已经定制了诸如CPU、内存和连接的ISO室等设置:
VMware产品(用于管理ESXi的ESXi和vCenter)支持通过Web服务接收外部API请求。您可以执行与vSphere客户端上相同的管理任务,例如创建新的虚拟机、创建新的vSwitch,甚至控制vm状态,但这次是通过支持的API进行的,该API具有许多语言的绑定,例如Python、Ruby和Go。
vSphere具有库存的特殊模型,其中的每个对象都具有特定的值。您可以访问此模型,并通过托管对象浏览器(MoB)查看基础设施的实际值。我们将使用VMware的官方Python绑定(pyvmomi)与此模型进行交互,并更改库存中的值(或创建它们)。
您可以单击任何超链接以查看更多详细信息并访问每个树或上下文中的每个叶。例如,单击Content.about以查看有关服务器的完整详细信息,例如确切的版本、构建和完整名称:
注意表的结构。第一列包含属性名称,第二列是该属性的数据类型,最后,第三列是实际运行值。
PyVmomi可以通过Pythonpip或不同仓库的系统包进行下载。
对于Python安装,请使用以下命令:
请注意,从pip下载的版本是6.5.2017.5-1,与vSphere发布的VMwarevSphere6.5相对应,但这并不意味着它不能与旧版本的ESXi一起使用。例如,我有VMwarevSphere5.5,它可以与最新的pyvmomi版本完美配合使用。
系统安装:
yuminstallpyvmomi-yPyvmomi库使用动态类型,这意味着IDE中的智能感知和自动完成功能等功能无法与其一起使用。您必须依赖文档和MoB来发现需要哪些类或方法来完成工作,但是一旦您发现它的工作原理,就会很容易使用。
首先,您需要通过提供用户名、密码和主机IP连接到ESXiMoB,并开始导航到MoB以获取所需的数据。这可以通过使用SmartConnectNoSSL()方法来完成:
frompyVim.connectimportSmartConnect,Disconnect,SmartConnectNoSSLESXi_connection=SmartConnectNoSSL(host="10.10.10.115",user="root",pwd='access123')请注意,还有另一种称为SmartConnect()的方法,当建立连接时必须向其提供SSL上下文,否则连接将失败。但是,您可以使用以下代码片段请求SSL不验证证书,并将此上下文传递给SmartConnect()的sslCContext参数:
importsslimportrequestscertificate=ssl.SSLContext(ssl.PROTOCOL_TLSv1)certificate.verify_mode=ssl.CERT_NONErequests.packages.urllib3.disable_warnings()为了严谨性和保持代码简洁,我们将使用内置的SmartConnectNoSSL()。
接下来,我们将开始探索MoB并在about对象中获取服务器的完整名称和版本。请记住,它位于content对象下,所以我们也需要访问它:
#!/usr/bin/python__author__="BassimAly"__EMAIL__="basim.alyy@gmail.com"frompyVim.connectimportSmartConnect,Disconnect,SmartConnectNoSSLESXi_connection=SmartConnectNoSSL(host="10.10.10.115",user="root",pwd='access123')full_name=ESXi_connection.content.about.fullNameversion=ESXi_connection.content.about.versionprint("ServerFullnameis{}".format(full_name))print("ESXiversionis{}".format(version))Disconnect(ESXi_connection)输出如下:
现在我们了解了API的工作原理。让我们进入一些严肃的脚本,并检索有关我们ESXi中部署的虚拟机的一些详细信息。
脚本如下:
#!/usr/bin/python__author__="BassimAly"__EMAIL__="basim.alyy@gmail.com"frompyVim.connectimportSmartConnect,Disconnect,SmartConnectNoSSLESXi_connection=SmartConnectNoSSL(host="10.10.10.115",user="root",pwd='access123')datacenter=ESXi_connection.content.rootFolder.childEntity[0]#FirstDatacenterintheESXi\virtual_machines=datacenter.vmFolder.childEntity#AccessthechildinsidethevmFolderprintvirtual_machinesformachineinvirtual_machines:print(machine.name)try:guest_vcpu=machine.summary.config.numCpuprint("TheGuestvCPUis{}".format(guest_vcpu))guest_os=machine.summary.config.guestFullNameprint("TheGuestOperatingSystemis{}".format(guest_os))guest_mem=machine.summary.config.memorySizeMBprint("TheGuestMemoryis{}".format(guest_mem))ipadd=machine.summary.guest.ipAddressprint("TheGuestIPAddressis{}".format(ipadd))print"================================="except:print("Can'tgetthesummary")在前面的示例中,我们做了以下事情:
脚本输出如下:
请注意,在本章的开头我们创建的python-vm虚拟机在最后一个截图中显示出来。您可以使用PyVmomi作为验证工具,与您的自动化工作流集成,验证虚拟机是否正在运行,并根据返回的输出做出决策。
这次我们将使用pyvmomi绑定来更改虚拟机状态。这将通过检查虚拟机名称来完成;然后,我们将导航到MoB中的另一个树,并获取运行时状态。最后,我们将根据其当前状态在机器上应用PowerOn()或PowerOff()函数。这将把机器状态从On切换到Off,反之亦然。
#!/usr/bin/python__author__="BassimAly"__EMAIL__="basim.alyy@gmail.com"frompyVim.connectimportSmartConnect,Disconnect,SmartConnectNoSSLESXi_connection=SmartConnectNoSSL(host="10.10.10.115",user="root",pwd='access123')datacenter=ESXi_connection.content.rootFolder.childEntity[0]#FirstDatacenterintheESXi\virtual_machines=datacenter.vmFolder.childEntity#AccessthechildinsidethevmFolderformachineinvirtual_machines:try:powerstate=machine.summary.runtime.powerStateif"python-vm"inmachine.nameandpowerstate=="poweredOff":print(machine.name)print("TheGuestPowerstateis{}".format(powerstate))machine.PowerOn()print("**PoweredOnthevirtualmachine**")elif"python-vm"inmachine.nameandpowerstate=="poweredOn":print(machine.name)print("TheGuestPowerstateis{}".format(powerstate))machine.PowerOff()print("**PoweredOffthevirtualmachine**")except:print("Can'texecutethetask")Disconnect(ESXi_connection)脚本输出如下:
此外,您还可以从vSphere客户端验证虚拟机状态,并检查以python-vm*开头的主机,将它们的电源状态从poweredOff更改为poweredOn:
Ansible还支持VMwareSDN产品(NSX)。AnsibleTower可以从VMwarevRealizeAutomation(vRA)访问,允许在不同工具之间实现完整的工作流集成。
以下是AnsiblePlaybook:
使用以下命令运行playbook:
#ansible-playbookesxi_create_vm.yml-vv以下是Playbook输出的截图:
您可以在vSphere客户端中验证虚拟机的创建和与CentOSISO文件的绑定:
您还可以通过更改剧本中“状态”中的值来更改现有虚拟机的状态,并从poweredon、poweredoff、restarted、absent、suspended、shutdownguest和rebootguest中进行选择。
VMware产品广泛用于IT基础设施中,为运行应用程序和工作负载提供虚拟化环境。与此同时,VMware还提供了许多语言的API绑定,可用于自动化管理任务。在下一章中,我们将探索另一个名为OpenStack的虚拟化框架,该框架依赖于红帽公司的KVMhypervisor。
长期以来,IT基础设施依赖于商业软件(来自VMWare、Microsoft和Citrix等供应商)提供运行工作负载和管理资源(如计算、存储和网络)的虚拟环境。然而,IT行业正在迈向云时代,工程师正在将工作负载和应用程序迁移到云(无论是公共还是私有),这需要一个能够管理所有应用程序资源的新框架,并提供一个开放和强大的API接口,以与其他应用程序的外部调用进行交互。
OpenStack提供了开放访问和集成,以管理所有计算、存储和网络资源,避免在构建云时出现供应商锁定。它可以控制大量的计算节点、存储阵列和网络设备,无论每个资源的供应商如何,并在所有资源之间提供无缝集成。OpenStack的核心思想是将应用于底层基础设施的所有配置抽象为一个负责管理资源的项目。因此,您将找到一个管理计算资源的项目(称为Nova),另一个提供实例网络的项目(neutron),以及与不同存储类型交互的项目(Swift和Cinder)。
您可以在此链接中找到当前OpenStack项目的完整列表
此外,OpenStack为应用程序开发人员和系统管理员提供统一的API访问,以编排资源创建。
在本章中,我们将探索OpenStack的新开放世界,并学习如何利用Python和Ansible与其交互。
表述状态转移(REST)依赖于HTTP协议在客户端和服务器之间传输消息。HTTP最初设计用于在请求时从Web服务器(服务器)向浏览器(客户端)传递HTML页面。页面代表用户想要访问的一组资源,并由统一资源标识符(URI)请求。
HTTP请求通常包含一个方法,该方法指示需要在资源上执行的操作类型。例如,当从浏览器访问网站时,您可以看到(在下面的屏幕截图中)方法是GET:
以下是最常见的HTTP方法及其用法:
应用程序开发人员可以公开其应用程序的某些资源,以供外部世界的客户端使用。携带请求从客户端到服务器并返回响应的传输协议是HTTP。它负责保护通信并使用服务器接受的适当数据编码机制对数据包进行编码,并且在两者之间进行无状态通信。
另一方面,数据包有效载荷通常以XML或JSON编码,以表示服务器处理的请求结构以及客户端偏好的响应方式。
对API的公共访问通常限制为特定数量的请求,无论是每小时还是每天,对于单个应用程序,以免过度使用公共资源。
Python提供了大量的工具和库来消耗API、编码消息和解析响应。例如,Python有一个requests包,可以格式化并发送HTTP请求到外部资源。它还有工具来解析JSON格式的响应并将其转换为Python中的标准字典。
Python还有许多框架可以将您的资源暴露给外部世界。Django和Flask是最好的之一,可以作为全栈框架。
OpenStack是一个免费的开源项目,用于基础设施即服务(IaaS),可以控制CPU、内存和存储等硬件资源,并为许多供应商构建和集成插件提供一个开放的框架。
我们的环境包括一台具有100GB存储、12个vCPU和32GBRAM的机器。该服务器将包含OpenStack控制器、计算和neutron角色在同一台服务器上。OpenStack服务器连接到具有我们自动化服务器的相同交换机和相同子网。请注意,这在生产环境中并不总是这样,但您需要确保运行Python代码的服务器可以访问OpenStack。
实验室拓扑如下:
在RHEL7.4和CentOS上安装rdo-OpenStack的步骤如下:
首先确保您的系统是最新的,然后从网站安装rdo-release.rpm以获取最新版本。最后,安装OpenStack-packstack软件包,该软件包将自动化OpenStack安装,如下段所示:
$sudoyuminstall-ycentos-release-OpenStack-queens$sudoyumupdate-y$sudoyuminstall-yOpenStack-packstack生成答案文件现在,您需要生成包含部署参数的答案文件。这些参数中的大多数都是默认值,但我们将更改一些内容:
#packstack--gen-answer-file=/root/EnterpriseAutomation编辑答案文件使用您喜欢的编辑器编辑EnterpriseAutomtion文件,并更改以下内容:
CONFIG_DEFAULT_PASSWORD=access123CONFIG_CEILOMETER_INSTALL=nCONFIG_AODH_INSTALL=nCONFIG_KEYSTONE_ADMIN_PW=access123CONFIG_PROVISION_DEMO=nCELIOMETER和AODH是OpenStack生态系统中的可选项目,可以在实验室环境中忽略。
我们还设置了一个用于生成临时令牌以访问API资源并访问OpenStackGUI的KEYSTONE密码
保存文件并通过packstack运行安装:
#packstackanswer-file=EnterpriseAutomation此命令将从Queens存储库下载软件包并安装OpenStack服务,然后启动它们。安装成功完成后,将在控制台上打印以下消息:
我们的云现在已经启动运行,准备接收请求。
OpenStack包含一系列服务,这些服务共同工作以管理虚拟机的创建、读取、更新和删除(CRUD)操作。每个服务都可以将其资源暴露给外部请求进行消费。例如,nova服务负责生成虚拟机并充当一个hypervisor层(虽然它本身不是一个hypervisor,但可以控制其他hypervisors,如KVM和vSphere)。另一个服务是glance,负责以ISO或qcow2格式托管实例镜像。neutron服务负责为生成的实例提供网络服务,并确保位于不同租户(项目)上的实例相互隔离,而位于相同租户上的实例可以通过覆盖网络(VxLAN或GRE)相互访问。
首先,我们需要在自动化服务器上安装Python绑定。这些绑定包含用于访问每个服务并使用从KEYSTONE生成的令牌进行身份验证的Python代码。此外,绑定包含每个项目的支持操作(如创建/删除/更新/列出):
yuminstall-ygccopenssl-develpython-pippython-wheelpipinstallpython-novaclientpipinstallpython-neutronclientpipinstallpython-keystoneclientpipinstallpython-glanceclientpipinstallpython-cinderclientpipinstallpython-heatclientpipinstallpython-OpenStackclient请注意,Python客户端名称为python-
您可以将其下载到站点的全局包或Pythonvirtualenv环境中。然后,您将需要OpenStack管理员权限,这些权限可以在OpenStack服务器内的以下路径中找到:
我们的Python脚本将如下所示:
OpenStack管理员可以在/etc/keystone/keystone.conf文件中配置admin_token字段,该字段永不过期。但出于安全原因,这在生产环境中不被推荐。
如果您不想将凭证存储在Python脚本中,可以将它们存储在ini文件中,并使用configparser模块加载它们。首先,在自动化服务器上创建一个creds.ini文件,并赋予适当的Linux权限,以便只能使用您自己的帐户打开它。
fromkeystoneauth1.identityimportv3fromkeystoneauth1importsessionimportConfigParserconfig=ConfigParser.ConfigParser()config.read("/root/creds.ini")auth=v3.Password(auth_url=config.get("os_creds","auth_url"),username=config.get("os_creds","username"),password=config.get("os_creds","password"),project_name=config.get("os_creds","project_name"),user_domain_name=config.get("os_creds","user_domain_name"),project_domain_name=config.get("os_creds","project_domain_name"))sess=session.Session(auth=auth,verify=False)print(sess)configparser模块将解析creds.ini文件并查看文件内部的os_creds部分。然后,它将使用get()方法获取每个参数前面的值。
config.get()方法将接受两个参数。第一个参数是.ini文件内的部分名称,第二个是参数名称。该方法将返回与参数关联的值。
此方法应该为您的云凭据提供额外的安全性。保护文件的另一种有效方法是使用Linux的source命令将keystonerc_admin文件加载到环境变量中,并使用os模块内的environ()方法读取凭据。
要使实例运行起来,OpenStack实例需要三个组件。由glance提供的引导镜像,由neutron提供的网络端口,最后是由nova项目提供的定义分配给实例的CPU数量、RAM数量和磁盘大小的计算flavor。
我们将首先下载一个cirros图像到自动化服务器。cirros是一个轻量级的基于Linux的图像,被许多OpenStack开发人员和测试人员用来验证OpenStack服务的功能:
脚本将如下所示:
您可以通过两种方式验证操作是否成功:
print("==========================ImageDetails==========================")forimageinglance.images.list(name="CirrosImage"):pprint(image){u'checksum':u'443b7623e27ecf03dc9e01ee93f67afe',u'container_format':u'bare',u'created_at':u'2018-04-11T03:11:58Z',u'disk_format':u'qcow2',u'file':u'/v2/images/3c2614b0-e53c-4be1-b99d-bbd9ce14b287/file',u'id':u'3c2614b0-e53c-4be1-b99d-bbd9ce14b287',u'min_disk':0,u'min_ram':0,u'name':u'CirrosImage',u'owner':u'8922dc52984041af8fe22061aaedcd13',u'protected':False,u'schema':u'/v2/schemas/image',u'size':12716032,u'status':u'active',u'tags':[],u'updated_at':u'2018-04-11T03:11:58Z',u'virtual_size':None,u'visibility':u'shared'}分配flavorFlavors用于确定实例的CPU、内存和存储大小。OpenStack带有一组预定义的flavors,具有从微小到超大的不同大小。对于cirros图像,我们将使用小型flavor,它具有2GBRAM,1个vCPU和20GB存储。访问flavors没有独立的API客户端;而是作为nova客户端的一部分。
您可以在OpenStackGUI|Admin|Flavors中查看所有可用的内置flavors:
为实例创建网络需要两件事:网络本身和将子网与之关联。首先,我们需要提供网络属性,例如ML2驱动程序(Flat、VLAN、VxLAN等),区分在同一接口上运行的网络之间的分段ID,MTU和物理接口,如果实例流量需要穿越外部网络。其次,我们需要提供子网属性,例如网络CIDR、网关IP、IPAM参数(如果定义了DHCP/DNS服务器)以及与子网关联的网络ID,如下面的屏幕截图所示:
现在我们将开发一个Python脚本来与neutron项目进行交互,并创建一个带有子网的网络
最后一部分是将所有内容粘合在一起。我们有引导镜像、实例规格和连接机器与其他实例的网络。我们准备使用nova客户端启动实例(记住nova负责虚拟机的生命周期和VM上的CRUD操作):
print("=================LaunchTheInstance=================")image_name=glance.images.get(image.id)network1=neutron.list_networks(name="python_network")instance_nics=[{'net-id':network1["networks"][0]["id"]}]server=nova.servers.create(name="python-instance",image=image_name.id,flavor=instance_flavor.id,nics=instance_nics,)status=server.statuswhilestatus=='BUILD':print("Sleeping5secondstilltheserverstatusischanged")time.sleep(5)instance=nova.servers.get(server.id)status=instance.statusprint(status)print("CurrentStatusis:{0}".format(status))在上述脚本中,我们使用了nova.servers.create()方法,并传递了生成实例所需的所有信息(实例名称、操作系统、规格和网络)。此外,我们实现了一个轮询机制,用于轮询nova服务的服务器当前状态。如果服务器仍处于BUILD阶段,则脚本将休眠五秒,然后再次轮询。当服务器状态更改为ACTIVE或FAILURE时,循环将退出,并在最后打印服务器状态。
脚本的输出如下:
Sleeping5secondstilltheserverstatusischangedSleeping5secondstilltheserverstatusischangedSleeping5secondstilltheserverstatusischangedCurrentStatusis:ACTIVE此外,您可以从OpenStackGUI|计算|实例中检查实例:
一旦您在自动化服务器上安装了shade,您将可以访问os-*模块,这些模块可以操作OpenStack配置,比如os_image(处理OpenStack镜像),os_network(创建网络),os_subnet(创建并关联子网到创建的网络),os_nova_flavor(根据RAM、CPU和磁盘创建flavors),最后是os_server模块(启动OpenStack实例)。
在自动化服务器上,使用Python的pip来下载和安装shade,以及所有依赖项:
pipinstallshade安装完成后,您将在Python的正常site-packages下拥有shade,但我们将使用Ansible。
此外,如果您之前没有在自动化服务器上安装Ansible,您将需要安装Ansible:
#yuminstallansible-y通过从命令行查询Ansible版本来验证Ansible是否已成功安装:
[root@AutomationServer~]#ansible--versionansible2.5.0configfile=/etc/ansible/ansible.cfgconfiguredmodulesearchpath=[u'/root/.ansible/plugins/modules',u'/usr/share/ansible/plugins/modules']ansiblepythonmodulelocation=/usr/lib/python2.7/site-packages/ansibleexecutablelocation=/usr/bin/ansiblepythonversion=2.7.5(default,Aug42017,00:39:18)[GCC4.8.520150623(RedHat4.8.5-16)]构建Ansibleplaybook正如我们在第十三章中所看到的,用于管理的Ansible,依赖于一个YAML文件,其中包含了您需要针对清单中的主机执行的一切。在这种情况下,我们将指示playbook在自动化服务器上建立与shade库的本地连接,并提供keystonerc_admin凭据,以帮助shade向我们的OpenStack服务器发送请求。
playbook脚本如下:
请注意,主机将是本地主机(或托管shade库的机器名称),同时我们在环境变量中添加了OpenStackkeystone凭据。
将playbook上传到自动化服务器并执行以下命令来运行它:
ansible-playbookos_playbook.ymlplaybook的输出将如下所示:
如今,IT行业正在尽可能地避免供应商锁定,转向开源世界。OpenStack为我们提供了窥视这个世界的窗口;许多大型组织和电信运营商正在考虑将其工作负载迁移到OpenStack,以在其数据中心构建私有云。然后,他们可以构建自己的工具来与OpenStack提供的开源API进行交互。
在下一章中,我们将探索另一个(付费的)公共亚马逊云,并学习如何利用Python来自动化实例创建。
在之前的章节中,我们探讨了如何使用Python自动化OpenStack和VMware私有云。我们将继续通过自动化最受欢迎的公共云之一——亚马逊网络服务(AWS)来继续我们的云自动化之旅。在本章中,我们将探讨如何使用Python脚本创建AmazonElasticComputeCloud(EC2)和AmazonSimpleStorageSystems(S3)。
AmazonEC2是一个可扩展的计算系统,用于为托管不同虚拟机(例如OpenStack生态系统中的nova-compute项目)提供虚拟化层。它可以与其他服务(如S3、Route53和AMI)通信,以实例化实例。基本上,您可以将EC2视为其他在虚拟基础设施管理器上设置的虚拟化程序(如KVM和VMware)之上的抽象层。EC2将接收传入的API调用,然后将其转换为适合每个虚拟化程序的调用。
AmazonMachineImage(AMI)是一个打包的镜像系统,其中包含了启动虚拟机所需的操作系统和软件包(类似于OpenStack中的Glance)。您可以从现有的虚拟机创建自己的AMI,并在需要在其他基础设施上复制这些机器时使用它,或者您可以简单地从互联网或亚马逊市场上选择公开可用的AMI。我们需要从亚马逊网络控制台获取AMIID,并将其添加到我们的Python脚本中。
在连接到AWS之前需要一些东西:
在使用Python脚本管理AWS时,访问密钥ID用于发送API请求并从API服务器获取响应。我们不会使用用户名或密码发送请求,因为它们很容易被他人捕获。此信息是通过下载创建用户名后出现的文本文件获得的。重要的是将此文件放在安全的位置并为其提供适当的Linux权限,以打开和读取文件内容。
另一种方法是在您的家目录下创建一个.aws目录,并在其中放置两个文件:credentials和config。第一个文件将同时包含访问密钥ID和秘密访问ID。
~/.aws/credentials如下所示:
[default]aws_access_key_id=AKIAIOSFODNN7EXAMPLEaws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY第二个文件将保存用户特定的配置,例如首选数据中心(区域),用于托管创建的虚拟机。在下面的示例中,我们指定要在us-west-2数据中心托管我们的机器。
配置文件~/.aws/config如下所示:
[default]region=us-west-2现在,安装boto3需要使用通常的pip命令来获取最新的boto3版本:
要验证模块是否成功安装,请在Python控制台中导入boto3,您不应该看到任何导入错误报告:
importboto3ec2=boto3.resource('ec2')instance=ec2.create_instances(ImageId='ami-824c4ee2',MinCount=1,MaxCount=1,InstanceType='m5.xlarge',Placement={'AvailabilityZone':'us-west-2'},)print(instance[0])在上面的示例中,以下内容适用:
输出如下:
打印的ID用于CRUD操作,以便稍后管理或终止实例。例如,我们可以使用之前创建的ec2资源提供的terminate()方法来终止实例:
AWS简单存储系统(S3)提供了安全和高度可扩展的对象存储服务。您可以使用此服务存储任意数量的数据,并从任何地方恢复它。系统为您提供了版本控制选项,因此您可以回滚到文件的任何先前版本。此外,它提供了RESTWeb服务API,因此您可以从外部应用程序访问它。
当数据传入S3时,S3将为其创建一个对象,并将这些对象存储在存储桶中(将它们视为文件夹)。您可以为每个创建的存储桶提供复杂的用户权限,并且还可以控制其可见性(公共、共享或私有)。存储桶访问可以是策略或访问控制列表(ACL)。
存储桶还存储有描述键值对中对象的元数据,您可以通过HTTPPOST方法创建和设置。元数据可以包括对象的名称、大小和日期,或者您想要的任何其他自定义键值对。用户帐户最多可以拥有100个存储桶,但每个存储桶内托管的对象大小没有限制。
与AWSS3服务交互时,首先要做的事情是创建一个用于存储文件的存储桶。在这种情况下,我们将S3提供给boto3.resource()。这将告诉boto3开始初始化过程,并加载与S3API系统交互所需的命令:
importboto3s3_resource=boto3.resource("s3")bucket=s3_resource.create_bucket(Bucket="my_first_bucket",CreateBucketConfiguration={'LocationConstraint':'us-west-2'})print(bucket)在前面的例子中,以下内容适用:
现在,我们需要利用创建的存储桶并将文件上传到其中。请记住,存储桶中的文件表示为对象。因此,boto3提供了一些包含对象作为其一部分的方法。我们将从使用put_object()开始。此方法将文件上传到创建的存储桶并将其存储为对象:
importboto3s3_resource=boto3.resource("s3")bucket=s3_resource.Bucket("my_first_bucket")withopen('~/test_file.txt','rb')asuploaded_data:bucket.put_object(Body=uploaded_data)在前面的例子中,以下内容适用:
要完成对存储桶的CRUD操作,我们需要做的最后一件事是删除存储桶。这是通过在我们的存储桶变量上调用delete()方法来实现的,前提是它已经存在,并且我们通过名称引用它,就像我们创建它并向其中上传数据一样。然而,当存储桶不为空时,delete()可能会失败。因此,我们将使用bucket_objects.all().delete()方法获取存储桶内的所有对象,然后对它们应用delete()操作,最后删除存储桶:
importboto3s3_resource=boto3.resource("s3")bucket=s3_resource.Bucket("my_first_bucket")bucket.objects.all().delete()bucket.delete()总结在本章中,我们学习了如何安装亚马逊弹性计算云(EC2),以及学习了Boto3及其安装。我们还学习了如何自动化AWSS3服务。
在下一章中,我们将学习SCAPY框架,这是一个强大的Python工具,用于构建和制作数据包并将其发送到网络上。
Scapy是一个强大的Python工具,用于构建和制作数据包,然后将其发送到网络。您可以构建任何类型的网络流并将其发送到网络。它可以帮助您使用不同的数据包流测试您的网络,并操纵从源返回的响应。
Scapy可以编程地将帧注入到流中并重新发送。例如,您可以将802.1qVLANID注入到流中并重新发送,以执行对网络的攻击或分析。此外,您可以使用Graphviz和ImageMagick模块可视化两个端点之间的对话并绘制图形。
Scapy有自己的领域特定语言(DSL),使用户能够描述他想要构建或操纵的数据包,并以相同的结构接收答案。这与Python内置的数据类型(如列表和字典)非常好地配合和集成。我们将在示例中看到,从网络接收的数据包实际上是一个Python列表,我们可以对它们进行常规列表函数的迭代。
Scapy支持Python2.7.x和3.4+,从Scapy版本2.x开始。但是,对于低于2.3.3的版本,Scapy需要Python2.5和2.7,或者3.4+用于之后的版本。由于我们已经安装了最新的Python版本,应该可以毫无问题地运行最新版本的Scapy。
此外,Scapy还有一个较旧的版本(1.x),已经不再支持Python3,仅在Python2.4上运行。
要获取最新版本,您需要使用pythonpip:
要验证Scapy是否成功安装,请访问Python控制台并尝试将scapy模块导入其中。如果控制台没有报告任何导入错误,则安装已成功完成:
需要一些附加软件包来可视化对话和捕获数据包。根据您的平台使用以下命令安装附加软件包:
运行以下命令安装附加软件包:
sudoapt-getinstalltcpdumpgraphvizimagemagickpython-gnuplotpython-cryptographypython-pyx在RedHat/CentOS上安装运行以下命令安装附加软件包:
yuminstalltcpdumpgraphvizimagemagickpython-gnuplotpython-cryptopython-pyx-y如果在基于CentOS的系统上找不到上述软件包中的任何一个,请安装epel存储库并更新系统。
正如我们之前提到的,Scapy有自己的DSL语言,与Python集成。此外,您可以直接访问Scapy控制台,并开始直接从Linuxshell发送和接收数据包:
请注意,有一些关于一些缺少的可选软件包的警告消息,例如matplotlib和PyX,但这应该没问题,不会影响Scapy的核心功能。
我们可以首先通过运行ls()函数来检查Scapy中支持的协议。列出所有支持的协议:
>>>ls()输出非常冗长,如果在此处发布,将跨越多个页面,因此您可以快速查看终端,以检查它。
现在让我们开发一个helloworld应用程序,并使用SCAPY运行它。该程序将向服务器的网关发送一个简单的ICMP数据包。我安装了Wireshark并配置它以监听将从自动化服务器(托管Scapy)接收流的网络接口。
现在,在Scapy终端上,执行以下代码:
>>>send(IP(dst="10.10.10.1")/ICMP()/"WelcometoEnterpriseAutomationCourse")返回到Wireshark,你应该看到通信:
让我们分析Scapy执行的命令:
请注意,我们没有在堆栈中指定以太网层,并且没有提供任何mac地址(源或目的地)。这在Scapy中默认填充,以创建一个有效的帧。它将自动检查主机ARP表,并找到源接口的mac地址(如果存在,也是目的地),然后将它们格式化为以太网帧。
在继续下一个示例之前,需要注意的最后一件事是,您可以使用与我们之前用于列出所有支持的协议的ls()函数相同的函数,以获取每个协议的默认值,然后在调用协议时将其设置为任何其他值。
现在让我们做一些更复杂(和邪恶的)事情!假设我们有两台路由器之间形成VRRP关系,并且我们需要打破这种关系以成为新的主机,或者至少在网络中创建一个抖动问题,如下拓扑图所示:
fromscapy.layers.inetimport*fromscapy.layers.vrrpimportVRRPvrrp_packet=Ether(src="00:00:5e:00:01:01",dst="01:00:5e:00:00:30")/IP(src="10.10.10.130",dst="224.0.0.18")/VRRP(priority=254,addrlist=["10.10.10.1"])sendp(vrrp_packet,inter=2,loop=1)在这个例子中:
脚本输出为:
Scapy还包含一些执行扫描的类。例如,您可以使用arping()在网络范围内执行ARP扫描,并在其中指定IP地址的正则表达式格式。Scapy将向这些子网上的所有主机发送ARP请求并检查回复:
根据接收到的数据包,只有一个主机回复SCAPY,这意味着它是扫描子网上唯一的主机。回复中列出了主机的mac地址和IP地址。
Scapy具有监听网络接口并捕获其所有传入数据包的能力。它可以以与tcpdump相同的方式将其写入pcap文件,但是Scapy提供了额外的函数,可以再次读取和重放pcap文件。
从简单的数据包重放开始,我们将指示Scapy读取从网络中捕获的正常pcap文件(使用tcpdump或Scapy本身)并将其再次发送到网络。如果我们需要测试网络的行为是否通过特定的流量模式,这将非常有用。例如,我们可能已经配置了网络防火墙以阻止FTP通信。我们可以通过使用Scapy重放的FTP数据来测试防火墙的功能。
在这个例子中,我们有捕获的FTPpcap文件,我们需要将其重新发送到网络:
fromscapy.layers.inetimport*frompprintimportpprintpkts=PcapReader("/root/ftp_data.pcap")#shouldbeinwireshark-tcpdumpformatforpktinpkts:pprint(pkt.show())PcapReader()将pcap文件作为输入,并对其进行分析,以单独获取每个数据包,并将其作为pkts列表中的一个项目添加。现在我们可以遍历列表并显示每个数据包的内容。
此外,您可以通过get_layer()函数获取特定层的信息,该函数访问数据包层。例如,如果我们有兴趣获取没有标头的原始数据,以便构建传输文件,我们可以使用以下脚本获取十六进制中所需的数据,然后稍后将其转换为ASCII:
fromscapy.layers.inetimport*frompprintimportpprintpkts=PcapReader("/root/ftp_data.pcap")#shouldbeinwireshark-tcpdumpformatftp_data=b""forpktinpkts:try:ftp_data+=pkt.get_layer(Raw).loadexcept:pass请注意,我们必须用try-except子句包围get_layer()方法,因为某些层不包含原始数据(例如FTP控制消息)。Scapy会抛出错误,脚本将退出。此外,我们可以将脚本重写为一个if子句,只有在数据包中包含原始层时才会向ftp_data添加内容。
在将数据包重新发送到网络之前,我们可以操纵数据包并更改其内容。由于我们的数据包实际上存储为列表中的项目,我们可以遍历这些项目并替换特定信息。例如,我们可以更改MAC地址、IP地址,或者为每个数据包或符合特定条件的特定数据包添加附加层。但是,我们应该注意,在特定层(如IP和TCP)中操纵数据包并更改内容将导致整个层的校验和无效,接收方可能因此丢弃数据包。
Scapy有一个令人惊奇的功能(是的,我知道,我多次说了令人惊奇,但Scapy确实是一个很棒的工具)。如果我们在pcap文件中删除原始内容,它将基于新内容自动为我们计算校验和。
因此,我们将修改上一个脚本并更改一些数据包参数,然后在发送数据包到网络之前重新构建校验和:
fromscapy.layers.inetimport*frompprintimportpprintpkts=PcapReader("/root/ftp_data.pcap")#shouldbeinwireshark-tcpdumpformatp_out=[]forpktinpkts:new_pkt=pkt.payloadtry:new_pkt[IP].src="10.10.88.100"new_pkt[IP].dst="10.10.88.1"del(new_pkt[IP].chksum)del(new_pkt[TCP].chksum)except:passpprint(new_pkt.show())p_out.append(new_pkt)send(PacketList(p_out),iface="eth0")在上一个脚本中:
此外,如果我们仍然在网关上运行Wireshark,我们会注意到Wireshark捕获了在重新计算后设置校验和值的ftp数据包流:
Scapy有一个名为sniff()的内置数据包捕获函数。默认情况下,如果您不指定任何过滤器或特定接口,它将监视所有接口并捕获所有数据包:
fromscapy.allimport*frompprintimportpprintprint("Begincapturingallpacketsfromallinterfaces.sendctrl+ctoterminateandprintsummary")pkts=sniff()pprint(pkts.summary())脚本输出为:
当然,您可以提供过滤器和特定接口来监视是否满足条件。例如,在前面的输出中,我们可以看到混合了ICMP、TCP、SSH和DHCP流量命中了所有接口。如果我们只对在eth0上获取ICMP流量感兴趣,那么我们可以提供过滤器和iface参数来嗅探函数,并且它将只过滤所有流量并记录只有ICMP的数据:
fromscapy.allimport*frompprintimportpprintprint("Begincapturingallpacketsfromallinterfaces.sendctrl+ctoterminateandprintsummary")pkts=sniff(iface="eth0",filter="icmp")pprint(pkts.summary())脚本输出如下:
请注意,我们只捕获eth0接口上的ICMP通信,所有其他数据包都由于应用在它们上的过滤器而被丢弃。iface值接受我们在脚本中使用的单个接口或要监视它们的接口列表。
sniff的高级功能之一是stop_filter,它是应用于每个数据包的Python函数,用于确定我们是否必须在该数据包之后停止捕获。例如,如果我们设置stop_filter=lambdax:x.haslayer(TCP),那么一旦我们命中具有TCP层的数据包,我们将停止捕获。此外,store选项允许我们将数据包存储在内存中(默认情况下已启用)或在对每个数据包应用特定函数后丢弃它们。如果您正在从SCAPY中获取来自线缆的实时流量,并且不希望将其写入内存,那么将sniff函数中的store参数设置为false,然后SCAPY将在丢弃原始数据包之前应用您开发的任何自定义函数(例如获取数据包的一些信息或将其重新发送到不同的目的地等)。这将在嗅探期间节省一些内存资源。
最后,我们可以将嗅探到的数据包写入标准的pcap文件,并像往常一样使用Wireshark打开它。这是通过一个简单的wrpcap()函数实现的,它将数据包列表写入pcap文件。wrpcap()函数接受两个参数——第一个是文件位置的完整路径,第二个是在使用sniff()函数之前捕获的数据包列表:
fromscapy.allimport*print("Begincapturingallpacketsfromallinterfaces.sendctrl+ctoterminateandprintsummary")pkts=sniff(iface="eth0",filter="icmp")wrpcap("/root/icmp_packets_eth0.pcap",pkts)摘要在本章中,我们学习了如何利用Scapy框架构建任何类型的数据包,包含任何网络层,并用我们的值填充它。此外,我们还看到了如何在接口上捕获数据包并重放它们。