惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
WordPress大学
WordPress大学
Google DeepMind News
Google DeepMind News
美团技术团队
大猫的无限游戏
大猫的无限游戏
H
Help Net Security
小众软件
小众软件
aimingoo的专栏
aimingoo的专栏
博客园 - 聂微东
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
M
MIT News - Artificial intelligence
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - Franky
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Security Blog
Microsoft Security Blog
F
Fortinet All Blogs
A
About on SuperTechFans
Recent Announcements
Recent Announcements
D
Docker
Vercel News
Vercel News
Engineering at Meta
Engineering at Meta
腾讯CDC
Martin Fowler
Martin Fowler
阮一峰的网络日志
阮一峰的网络日志

Sam's lab

python 100 lines of code, bulk config of network devices (II) - Sam's lab python 100 lines of code, bulk config of network devices (II) - Sam's lab Homelab | files sharing apps — Send&Pingvin Share - Sam's lab Homelab | files sharing apps — Send&Pingvin Share - Sam's lab Homelab | Low-level design—Proxmox - Sam's lab Homelab | Low-level design—Proxmox - Sam's lab Homelab | Low-level design –Nginx Reverse Proxy - Sam's lab Homelab | Low-level design –Nginx Reverse Proxy - Sam's lab Homelab | Architecture Design and Implementation – High-level design - Sam's lab Homelab | Architecture Design and Implementation – High-level design - Sam's lab Typecho | Migrated - Sam's lab Typecho | Migrated - Sam's lab Let’s Encrypt | Wildcard Certificates - Sam's lab Let’s Encrypt | Wildcard Certificates - Sam's lab Python | Monitoring, Alarms - Sam's lab Python | Monitoring, Alarms - Sam's lab PVE | Managing Virtual Machines via rest api - Sam's lab Python ORM | peewee - Sam's lab Python ORM | peewee - Sam's lab
PVE | Managing Virtual Machines via rest api - Sam's lab
sam · 2022-08-07 · via Sam's lab

结合python 和 pve 的api,方便的管理虚拟机,可以单独的开发个小脚本,也可以嵌入到任何其他系统内,作为一个小功能。

介绍

关于pve rest api的官方介绍和 api文档:

https://pve.proxmox.com/wiki/Proxmox_VE_API

https://pve.proxmox.com/pve-docs/api-viewer/index.html#/nodes/{node}/qemu/{vmid}/status/stop

调用pve api ,有两种认证方式

  1. Ticket Cookie

先发送一个包含用户名密码的POST,然后server会返回json格式认证信息,提取必要信息并附加到下次http request请求头部即可

该ticket权限等同于对应用户的权限,两小时后超时失效

shell 命令

curl -k -d 'username=root@pam' --data-urlencode 'password=xxxxxxxx' https://192.168.0.101:8006/api2/json/access/ticket

python脚本

import requests


# solving self-sign CA warning
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
       
path = '/api2/json/access/ticket'
url = 'https://' + ip + ':' + port + path
r = requests.post(url=url, json={"username": username, "password": password}, verify=False)
print(r.json())

Postman(Talend API Tester )

返回格式

  {
    "data":{
    "ticket": "PVE:root@pam:62EF3DBE::UPduHl969t0bv/eVUs54Ez5z86epC86WvUi81kAgGbs/zw2aZbD7l2loroqOV58/u+iZFrCFRlEsvIKDYskSx0NWM4eW7081u4eMHquHPOnfwm1fblUnIClfs0tNjxwA7ZmFTVsNDgvEPFG5Uw98K8sYDvHLHixSHQEU8+MUyRubeYaJCTNSzNW2FhX+gVZU3xe7hUZSAO2wo0BI5Ciz2tK8WFtAoh7o4UyLR0nJb8qCf1XV6SWUxrq4NpwnmcqEUg7GIjS4ueZ874tjbvnLUdBF62aiKVdECZjAtbxv3ocqKUlw1jN/Gl6xDfSEpgwQiQCKjG2gMdPrNdu9Fp2Tow==",
    "cap":{"vms":{"VM.Clone": 1, "VM.Backup": 1, "VM.Config.Options": 1, "VM.Snapshot": 1,…},
    "CSRFPreventionToken": "62EF3DBE:/7meKBIZRMV6lpaQ9G9uylNI+/5qHYq3+gDj1Oie6Tw",
    "username": "root@pam"
    }
    }
  1. API Tokens

手动从PVE GUI控制台创建,并赋予合适的权限,可以设置超期时间(可以永久),记下token信息,后续把token信息附件到HTTP request 头部即可

添加token

添加权限

通过API操作PVE

例如,认证信息获取之后,通过api 查看当前pve node 虚拟机列表

  1. Ticket Cookie 方式

查询所有节点名称

        ticket = {.................}
        path = '/api2/json/nodes'
        url = 'https://' + ip + ':' + port + path
        headers = {'CSRFPreventionToken': ticket['data']['CSRFPreventionToken'], 'Cookie': 'PVEAuthCookie=' + ticket['data']['ticket']}
        r = requests.get(url=url, headers=headers, verify=False)
        print(r.json())

返回格式

{
    "data": [
        {
            "id": "node/pve01",
            "maxcpu": 4,
            "status": "online",
            "type": "node",
            "node": "pve01",
            "maxdisk": 100861726720,
            "cpu": 0.0333665338645418,
            "disk": 41166532608,
            "uptime": 2235423,
            "mem": 6703284224,
            "level": "",
            "maxmem": 8073363456,
            "ssl_fingerprint": "1F:D1:48:1A:46:19:2F:92:A1:70:3B:4A:EC:FA:67:FA:91:83:4E:5B:AF:68:92:4A:6C:8A:6F:83:D6:66:96:CB"
        }
    ]
}

查询特定节点下虚拟机列表

        ticket = {.................}
        node = 'pve01'
        path = f'/api2/json/nodes/{node}/qemu'
        url = 'https://' + ip + ':' + port + path
        headers = {'CSRFPreventionToken': ticket['data']['CSRFPreventionToken'], 'Cookie': 'PVEAuthCookie=' + ticket['data']['ticket']}
        r = requests.get(url=url, headers=headers, verify=False)
        print(r.json())

返回格式

{
"data":[
{"pid": 2648205, "cpus": 2, "status": "running", "name": "OpenMediaVault",…},
{"disk": 0, "mem": 1316534861, "cpu": 0.0445637817533544, "diskread": 0, "diskwrite": 0,…},
{"mem": 3197312520, "cpu": 0.118665826973757, "disk": 0, "maxmem": 4294967296, "maxdisk": 53687091200,…},
{"pid": 1400, "cpus": 1, "status": "running", "name": "OpenWRT",…},
{"cpus": 1, "status": "stopped", "name": "openwrt-test", "vmid": 104,…}
]
}
  1. Token 方式

查询所有节点名称

        path = '/api2/json/nodes'
        token = '...........'
        url = 'https://' + ip + ':' + port + path
        headers = {'Authorization': 'PVEAPIToken=' + token} # Authorization : PVEAPIToken=root@pam!myid=1e1b7cbd-e7eqweq553141525564c-c324519041e0
        r = requests.get(url=url, headers=headers, verify=False)
        print(r.json())

查询特定节点下虚拟机列表

        token = '...........'
        node = 'pve01'
        path = f'/api2/json/nodes/{node}/qemu'
        url = 'https://' + ip + ':' + port + path
        headers = {'Authorization': 'PVEAPIToken=' + token} # Authorization : PVEAPIToken=root@pam!myid=1e1b7cbd-e7eqweq553141525564c-c324519041e0
        r = requests.get(url=url, headers=headers, verify=False)
        print(r.json())

附上完整代码,

import requests


# self-sign CA warning
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

class Pve_api(object):

    def __init__(self, ip, username = None, password = None, port = '8006'):
        self.ip = ip
        self.username = username
        self.password = password
        self.port = port
        self.ticket = None

    '''
    ####### ticket data structure
    {
    "data":{
    "ticket": "PVE:root@pam:62EF3DBE::UPduHl969t0bv/eVUs54Ez5z86epC86WvUi81kAgGbs/zw2aZbD7l2loroqOV58/u+iZFrCFRlEsvIKDYskSx0NWM4eW7081u4eMHquHPOnfwm1fblUnIClfs0tNjxwA7ZmFTVsNDgvEPFG5Uw98K8sYDvHLHixSHQEU8+MUyRubeYaJCTNSzNW2FhX+gVZU3xe7hUZSAO2wo0BI5Ciz2tK8WFtAoh7o4UyLR0nJb8qCf1XV6SWUxrq4NpwnmcqEUg7GIjS4ueZ874tjbvnLUdBF62aiKVdECZjAtbxv3ocqKUlw1jN/Gl6xDfSEpgwQiQCKjG2gMdPrNdu9Fp2Tow==",
    "cap":{"vms":{"VM.Clone": 1, "VM.Backup": 1, "VM.Config.Options": 1, "VM.Snapshot": 1,…},
    "CSRFPreventionToken": "62EF3DBE:/7meKBIZRMV6lpaQ9G9uylNI+/5qHYq3+gDj1Oie6Tw",
    "username": "root@pam"
    }
    }

    '''


    def get_ticket(self):
        path = '/api2/json/access/ticket'
        url = 'https://' + self.ip + ':' + self.port + path
        r = requests.post(url=url, json={"username": self.username, "password": self.password}, verify=False)
        self.ticket = r.json() # dict rather than string
        return r.json()

    def ticket_node_list(self):
        path = '/api2/json/nodes'
        url = 'https://' + self.ip + ':' + self.port + path
        headers = {'CSRFPreventionToken': self.ticket['data']['CSRFPreventionToken'], 'Cookie': 'PVEAuthCookie=' + self.ticket['data']['ticket']}
        r = requests.get(url=url, headers=headers, verify=False)
        return r.json()


    def ticket_vm_list(self, node):
        path = f'/api2/json/nodes/{node}/qemu'
        url = 'https://' + self.ip + ':' + self.port + path
        headers = {'CSRFPreventionToken': self.ticket['data']['CSRFPreventionToken'], 'Cookie': 'PVEAuthCookie=' + self.ticket['data']['ticket']}
        r = requests.get(url=url, headers=headers, verify=False)
        return r.json()

    def ticket_vm_current(self, node, vmid):
        path = f'/api2/json/nodes/{node}/qemu/{vmid}/status/current'
        url = 'https://' + self.ip + ':' + self.port + path
        headers = {'CSRFPreventionToken': self.ticket['data']['CSRFPreventionToken'], 'Cookie': 'PVEAuthCookie=' + self.ticket['data']['ticket']}
        r = requests.get(url=url, headers=headers, verify=False)
        return r.json()

    def ticket_vm_start(self, node, vmid):
        path = f'/api2/json/nodes/{node}/qemu/{vmid}/status/start'
        url = 'https://' + self.ip + ':' + self.port + path
        headers = {'CSRFPreventionToken': self.ticket['data']['CSRFPreventionToken'], 'Cookie': 'PVEAuthCookie=' + self.ticket['data']['ticket']}
        r = requests.post(url=url, headers=headers, verify=False)
        return r.json()

    def token_vm_stop(self, node, vmid, token):
        path = f'/api2/json/nodes/{node}/qemu/{vmid}/status/stop'
        url = 'https://' + self.ip + ':' + self.port + path
        headers = {'Authorization': 'PVEAPIToken=' + token} # Authorization : PVEAPIToken=root@pam!myid=1e1b7cbd-e7553141525564c-c324519041e0
        r = requests.post(url=url, headers=headers, verify=False)
        return r.json()


if __name__ == '__main__':
    op = Pve_api(ip='192.168.0.101', username='root@pam', password='xxxxxx')
    print(op.ticket)
    # it must run 'get_ticket()' first to get a new ticket when you do the 'op' down below
    # op.get_ticket()
    # print(op.ticket)
    # print('@'*10)
    # print(op.ticket_node_list())
    # print('@'*10)
    # print(op.ticket_vm_list('pve01'))
    # print('@'*10)
    # print(op.ticket_vm_current('pve01', '104'))
    # print('@'*10)
    # print(op.ticket_vm_start('pve01', '104'))
    # print('@'*10)
    # print(op.token_vm_stop('pve01', '104', 'root@pam!myid=1e1b7cbd-e755-4171-b32c-c324519041e0'))

更多相关代码和资料在这个仓库

https://github.com/sshuangliu/Proxmox-VE-api

Post Views: 4,045