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

推荐订阅源

P
Palo Alto Networks Blog
T
The Blog of Author Tim Ferriss
Engineering at Meta
Engineering at Meta
博客园_首页
博客园 - 三生石上(FineUI控件)
G
Google Developers Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 【当耐特】
Microsoft Security Blog
Microsoft Security Blog
P
Privacy & Cybersecurity Law Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
S
Secure Thoughts
爱范儿
爱范儿
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
H
Help Net Security
The Cloudflare Blog
Recorded Future
Recorded Future
Attack and Defense Labs
Attack and Defense Labs
J
Java Code Geeks
O
OpenAI News
T
Tor Project blog
B
Blog RSS Feed
D
Darknet – Hacking Tools, Hacker News & Cyber Security
PCI Perspectives
PCI Perspectives
V
Visual Studio Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
A
About on SuperTechFans
www.infosecurity-magazine.com
www.infosecurity-magazine.com
W
WeLiveSecurity
Cyberwarzone
Cyberwarzone
云风的 BLOG
云风的 BLOG
Security Latest
Security Latest
S
Schneier on Security
Know Your Adversary
Know Your Adversary
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
Vulnerabilities – Threatpost
D
DataBreaches.Net
宝玉的分享
宝玉的分享
T
Troy Hunt's Blog
V
V2EX
Cisco Talos Blog
Cisco Talos Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
美团技术团队
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Latest news
Latest news
量子位
Microsoft Azure Blog
Microsoft Azure Blog

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