python3 aptly api

import requests
import json
from aptly_api.client import Client as AptlyCilent



class Aptly(object):
    def __init__(self):
        self.host = 'http://192.168.88.128'
        self.port = 8080
        self.timeout = 300
        self.base_url = f"{self.host}:{self.port}"

    def _req_get(self, api, params=None):
        response = requests.get(f'{self.base_url}{api}', timeout=self.timeout)
        if response.status_code < 200 or response.status_code >= 300:
            return False, f"API request failed with status code: {response.status_code} "
        else:
            return True, response.json()

    def _req_post(self, api, data=None, params=None):
        headers = {'Content-Type': 'application/json'}
        response = requests.post(f'{self.base_url}{api}', data=data, headers=headers, params=params, timeout=self.timeout)
        if response.status_code < 200 or response.status_code >= 300:
            return False, f"API request failed with status code: {response.status_code} {response.json()}"
        else:
            return True, response.json()

    def _req_post_file(self, api, data):
        # headers = {
        #         'Content-Type': 'application/octet-stream',  # 设置内容类型为二进制流文件
        #     }
        response = requests.post(f'{self.base_url}{api}', files=data, timeout=self.timeout)
        if response.status_code < 200 or response.status_code >= 300:
            return False, f"API request failed with status code: {response.status_code} {response.json()}"
        else:
            return True, response.json()

    def _req_put(self, api, data, params=None):
        headers = {'Content-Type': 'application/json'}
        response = requests.put(f'{self.base_url}{api}', data=json.dumps(data), headers=headers, params=params, timeout=self.timeout)
        if response.status_code < 200 or response.status_code >= 300:
            return False, f"API request failed with status code: {response.status_code} {response.json()}"
        else:
            return True, response.json()

    def _req_delete(self, api, json=None, params=None):
        response = requests.delete(f'{self.base_url}{api}', json=json, params=params,timeout=self.timeout)
        if response.status_code < 200 or response.status_code >= 300:
            return False, f"API request failed with status code: {response.status_code} {response.json()}"
        else:
            return True, response.json()

    def create_repo(self, name, comment=None, defaultDistribution=None, defaultComponent='main'):
        '''
        :param name: 仓库名
        :param comment: 仓库说明
        :param defaultDistribution: 类似reprepro中的codename
        :param defaultComponent: 通常会有main(主要), contrib(贡献), non-free(非自由)等, 默认main
        :return:
        curl -X POST -H 'Content-Type: application/json' --data '{"Name": "aptly-repo"}' http://localhost:8080/api/repos
        {"Name":"aptly-repo","Comment":"","DefaultDistribution":"","DefaultComponent":""}
        命令: aptly repo create  <name>  参数:-comment="" -distribution="" -component="main"

        eg:
            # repo = aptly.create_repo('nfs5','5.0','nfs5','main')
        '''
        body = {}
        body["Name"] = name
        if comment:
            body["Comment"] = comment
        if defaultDistribution:
            body["DefaultDistribution"] = defaultDistribution
        if defaultComponent:
            body["DefaultComponent"] = defaultComponent
        is_ok, res = self._req_post(f'/api/repos/',body)
        if is_ok:
            return res
        return is_ok

    def edit_repo(self, name, comment=None, defaultDistribution=None, defaultComponent=None):
        '''
        :param name: 仓库名
        :param comment: 仓库说明
        :param defaultDistribution: 类似reprepro中的codename
        :param defaultComponent: 通常会有main(主要), contrib(贡献), non-free(非自由)等, 默认main
        :return:
        curl -X PUT -H 'Content-Type: application/json' --data '{"DefaultDistribution": "trusty"}' http://localhost:8080/api/repos/local1
        {"Name":"local1","Comment":"","DefaultDistribution":"trusty","DefaultComponent":"main"}

        eg: # repo = aptly.edit_repo('myrepo', comment='test myrepo')
        '''
        body = {}
        if comment:
            body["Comment"] = comment
        if defaultDistribution:
            body["DefaultDistribution"] = defaultDistribution
        if defaultComponent:
            body["DefaultComponent"] = defaultComponent
        is_ok, res = self._req_put(f'/api/repos/{name}', body)
        if is_ok:
            return res
        return is_ok

    def delete_repo(self, name, force=False):
        '''

        :param name:
        :param force:
        :return:
        eg: repo = aptly.delete_repo('nfs5')
        '''
        is_ok, res = self._req_delete(f'/api/repos/{name}', params={"force": "1" if force else "0"})
        print(res)
        if is_ok:
            return res
        return is_ok

    def show_repos(self):
        '''
        :return:
        curl http://localhost:8080/api/repos
        eg: repos = aptly.show_repos()
        '''
        is_ok, res = self._req_get(f'/api/repos')
        if is_ok:
            return res
        return is_ok

    def show_repo(self, name):
        '''
        :param name: 仓库名
        :return:
        curl http://localhost:8080/api/repos/aptly-repo
        {"Name":"aptly-repo","Comment":"","DefaultDistribution":"","DefaultComponent":""}
        命令: aptly repo show <name>  参数:-with-packages
        eg: aptly.show_repo('nfs5')
        '''
        is_ok, res = self._req_get(f'/api/repos/{name}')
        if is_ok:
            return res
        return is_ok

    def search_packages(self, key):
        '''

        :param key:
        :return:
        {
            'Architecture': 'amd64',
            'Description': ' 腾讯QQ Linux版本。\n',
            'Filename': 'linuxqq_2.0.0-b2-1089_amd64.deb',
            'FilesHash': '805665250fdd288f',
            'Homepage': 'https://im.qq.com/linuxqq',
            'Installed-Size': '35452',
            'Key': 'Pamd64 linuxqq 2.0.0-b2 805665250fdd288f',
            'MD5sum': 'c521b08830eaccba0d0ac2f7de374606',
            'Maintainer': 'Tencent <support@tencent.com>',
            'Package': 'linuxqq',
            'Priority': 'optional',
            'Recommends': 'tint2',
            'SHA1': '5f46a467911b198e77e6e303c4ebb2499733c253',
            'SHA256': 'f8e96b0fa3a09f7d36385a446ddfd86b173cf1cef1eb0f40493250538807c52c',
            'SHA512': '42ab8fdecdc2782f8411415d62854f61a8f11b152031672cf43fcb95757bbb55a9c5856c300628428a33ae1a40516acc8e37222f422bf4c75736da40c9e5fabe',
            'Section': 'Internet',
            'ShortKey': 'Pamd64 linuxqq 2.0.0-b2',
            'Size': '12393292',
            'Version': '2.0.0-b2'
        }
        eg: # pakcages = aptly.search_packages('Pamd64 linuxqq 2.0.0-b2 805665250fdd288f')
        '''
        is_ok, res = self._req_get(f'/api/packages/{key}')
        if is_ok:
            return res
        return is_ok

    def get_repo_packages(self, name):
        '''

        :param name:
        :return:
        '''
        is_ok, res = self._req_get(f'/api/repos/{name}/packages')
        if is_ok:
            packages = []
            for key in res:
                packages.append(self.search_packages(key))
            return packages
        return is_ok

    def add_package(self, repo, files, force_replace=False, remove_processed_files=True):
        """
        :param repo: 仓库
        :param files: 上传的软件列表
        :param force_replace: 若上的软件与仓库里的冲突是否强制替换
        :param remove_processed_files: 上传的文件默认存放在 f'/opt/aptly/upload/{repo}',上传后是否立即删除
        :return:
        success: (True, {'FailedFiles': [], 'Report': {'Warnings': [], 'Added': ['linuxqq_3.1.2-13107_amd64 added'], 'Removed': []}})
        failed: (True, {'FailedFiles': ['/opt/aptly/upload/nfs4/linuxqq_1.1.2-13107_amd64.deb'], 'Report': {'Warnings': ['Unable to add package to repo linuxqq_3.1.2-13107_amd64: conflict in package linuxqq_3.1.2-13107_amd64'], 'Added': [], 'Removed': []}})
        源命令: aptly repo add testing files/libboost-program-options-dev_1.49.0.1_i386.deb
        上传得文件所在位置 : f'/opt/aptly/upload/{repo}'
        """
        # eg:  res = aptly.add_package('nfs4',[
        #                \Users\apple\develop\py\demo\linuxqq_1.1.2-13107_amd64.deb,
        #                 \Users\apple\develop\py\demo\nginx_1.18.0-6.1+nfs5_all.deb
        #             ])

        base_upload_path = f'/opt/aptly/upload/{repo}/'
        params = {
            "noRemove": "0" if remove_processed_files else "1",
        }
        if force_replace:
            params["forceReplace"] = "1"

        to_upload = []
        for f in files:
            fh = open(f, mode="rb")
            to_upload.append((f, fh),)
        # pkg_file = {
        #     'file':open(files, 'rb')
        # }
        _, uploaded_file = self._req_post_file(f'/api/files/{repo}',to_upload)
        # 关闭文件
        for fn, to_close in to_upload:
            if not to_close.closed:
                to_close.close()

        success_deb = []
        failed_deb = []
        for deb in uploaded_file:
            res = self._req_post(f"/api/repos/{repo}/file/{deb}",params=params)
            # /api/repos/nfs4/file/nfs4/linuxqq_3.1.2-13107_amd64.deb 单个包上传
            # /api/repos/nfs4/file/nfs4/ 将nfs4 目录下的deb包批量上传
            print(res)
            if res[1].get('FailedFiles'):
                failed_msg = res[1].get('Report').get('Warnings')
                deb_name = res[1].get('FailedFiles')[0].split(base_upload_path)[1]
                failed_deb.append({deb_name:failed_msg})
            else:
                deb_name = res[1].get('Report').get('Added')[0].split(' added')[0]

                success_deb.append({deb_name:True})
        return {'success':success_deb, 'failed':failed_deb}

    def delete_packages_by_key(self,repo, pkg_key):
        '''

        :param repo:
        :param file:
        :return:
        源命令:
            aptly repo remove nfs4 linuxqq_1.1.2-13107_amd64.deb  参数: -dry-run 试运行,可查看命令会将删除的deb包
            aptly repo remove nfs4 linuxqq   默认匹配 linuxqq*
        '''
        # self._req_delete(f"/api/files/{repo}", file)
        is_ok, resp = self._req_delete(f"/api/repos/{repo}/packages", json={
            "PackageRefs": pkg_key,
        })
        if is_ok:
            return resp
        return resp

    def delete_file(self, repo, deb):
        '''

        :param repo:
        :param deb:
        :return:
        eg:
            /opt/aptly/upload/nfs4/linuxqq_1.1.2-13107_amd64.deb
        '''
        self._req_post(f"/api/files/{repo}/{deb}")


if __name__ == '__main__':

    '''
    === repo ===
    *** 查看所有仓库 ***
    # aptly repo list
    List of local repos:
     * [myrepo]: test myrepo (packages: 2)
     * [nfs4]: 4.0 (packages: 2)
    
    *** 查看<name>仓库信息 ***
    # aptly repo show nfs4  
    Name: nfs4
    Comment: 4.0
    Default Distribution: nfs4
    Default Component: main
    Number of packages: 2

    *** 查看<name>仓库信息,包括仓库内的deb包 ***
    # aptly repo show  -with-packages nfs4
    Name: nfs4
    Comment: 4.0
    Default Distribution: nfs4
    Default Component: main
    Number of packages: 2
    Packages:
      linuxqq_3.1.2-13107_amd64
      nginx_1.18.0-6.1+nfs5_all

    === publish ===
    *** 查看所有已经发布的仓库 ***
    # aptly publish list     
    Published repositories:
      * ./nfs4 [amd64] publishes {main: [nfs4]: 4.0}

    *** 发布仓库 ***
    # aptly publish repo -distribution=nfs4 nfs4
    Loading packages...
    Generating metadata files and linking package files...
    Finalizing metadata files...
    Signing file 'Release' with gpg, please enter your passphrase when prompted:
    
    You need a passphrase to unlock the secret key for
    user: "First Last (Aptly Repo Signing) <test@test.com>"
    4096-bit RSA key, ID 2B5CE95B, created 2023-07-05
    
    Local repo nfs4 has been successfully published.
    Please setup your webserver to serve directory '/opt/aptly/public' with autoindexing.
    Now you can add following line to apt sources:
      deb http://your-server/ nfs4 main
    Don't forget to add your GPG key to apt with apt-key.
    
    You can also use `aptly serve` to publish your repositories over HTTP quickly.

    *** 查看发布的仓库 ***
    # aptly publish show nfs4
    Prefix: .
    Distribution: nfs4
    Architectures: amd64
    Sources:
      main: nfs4 [local]
    
    *** 取消发布 ***
    # aptly publish drop nfs4
    Removing /opt/aptly/public/dists...
    Removing /opt/aptly/public/pool...
    
    Published repository has been removed successfully.

    
    '''

    aptly = Aptly()
    repo = aptly.create_repo('nfs5','5.0','nfs5','main')
    print(repo)

    repo = aptly.edit_repo('myrepo', comment='test myrepo')
    print(repo)

    repo = aptly.delete_repo('nfs5')

    repos = aptly.show_repos()
    print(repos)

    repo = aptly.show_repo('nfs4')
    print(repo)

    pakcages = aptly.search_packages('Pamd64 linuxqq 2.0.0-b2 805665250fdd288f')

    res = aptly.add_package('nfs4',[
        r'C:\Users\apple\develop\py\demo\linuxqq_3.1.2-13107_amd64.deb',
        r'C:\Users\apple\develop\py\demo\nginx_1.18.0-6.1+nfs5_all.deb'
    ])
    print(res)

    aptly.delete_packages_by_key('nfs4',['Pamd64 linuxqq 3.1.2-13107 77650f003cb39465'])

    packages = aptly.get_repo_packages('nfs4')
    print(packages)
    print(len(packages))



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值