yuanying
1/17/2018 - 7:19 AM

Research of OpenStack policies

Research of OpenStack policies

from nova import policies
from oslo_policy import policy
import openpyxl as px
import re
import os

ps = {}
rules = set()

translation_dict = {
    'extensions': 'コンピュート拡張',
    'flavors': 'フレーバー',
    'limits': 'コンピュート制限',
    'os-aggregates': 'ホストアグリゲート',
    'os-assisted-volume-snapshots': 'スナップショットアシスト',
    'os-availability-zone': 'アベイラビリティゾーン',
    'os-cells': 'セル',
    'os-console-auth-tokens': 'コンソール認証トークン',
    'os-floating-ip-dns': 'フローティングIP DNS',
    'os-hypervisors': 'ハイパーバイザー',
    'os-instance_usage_audit_log': 'インスタンス使用量ログ',
    'os-keypairs': 'キーペア',
    'os-migrations': 'マイグレーション',
    'os-quota-class-sets': 'クォータクラスセット',
    'os-quota-sets': 'クォータクラス',
    'os-server-external-events': '仮想マシン外部イベント',
    'os-server-groups': '仮想マシングループ',
    'os-services': 'コンピュートサービス',
    'os-simple-tenant-usage': 'テナント使用量サマリ',
    'servers': '仮想マシン',
    'rule:os_compute_api:os-server-groups': '管理者/テナントユーザ',
    'is_admin:True': '管理者',
    'rule:os_compute_api:os-flavor-manage': '管理者',
    'rule:admin_or_owner': '管理者/テナントユーザ',
    'rule:admin_api or user_id:%(user_id)s': '管理者/テナントユーザ',
    'is_admin:True or quota_class:%(quota_class)s': '管理者',
    '@': '-',
    'rule:admin_api': '管理者',

    'sync_instances': '仮想サーバ情報の同期',

    'addTenantAccess': 'テナントアクセスの追加',
    'removeTenantAccess': 'テナントアクセスの削除',
    'set_metadata': 'メタデータの作成',
    'add_host': 'ホストの追加',
    'remove_host': 'ホストの削除',
    'os-resetState': '状態のリセット',
    'injectNetworkInfo': 'ネットワーク情報の追加',
    'resetNetwork': 'ネットワークのリセット',
    'changePassword': 'パスワード変更',
    'os-getConsoleOutput': 'コンソールの表示',
    'createBackup': 'バックアップの作成',
    'evacuate': 'エバキュエート',
    'lock': 'ロック',
    'unlock': 'アンロック',
    'migrate': 'マイグレーション',
    'os-migrateLive': 'ライブマイグレーション',
    'pause': 'ポーズ',
    'unpause': 'アンポーズ',
    'confirmResize': 'リサイズの確定',
    'revertResize': 'リサイズの中止',
    'reboot': '再起動',
    'resize': 'リサイズ',
    'rebuild': 'リビルド',
    'createImage': 'イメージの作成',
    'os-start': '起動',
    'os-stop': '停止',
    'trigger_crash_dump': 'クラッシュダンプ',
    'shelve': 'シェルブ',
    'unshelve': 'アンシェルブ',
    'shelveOffload': 'シェルブの削除',
    'resume': 'レジューム',
    'suspend': 'サスペンド',

    'os-extra_specs': 'エクストラスペック',
    'os-interface': 'インタフェース',
    'consoles': 'コンソール',
    'metadata': 'メタデータ',
    'migrations': 'マイグレーション',
    'os-volume_attachments': 'ボリュームアタッチメント',
}

def t(k):
    return translation_dict.get(k, k)

def f(op):
    if len(op) > 1:
        methods = set()
        for o in op:
            methods.add(o['method'])
        if len(methods) == 1 and 'GET' in methods:
            return '表示'
        return '管理'
    else:
        p = op[0]
        if p['method'] == 'GET':
            return '表示'
        elif p['method'] == 'PUT':
            return '更新'
        elif p['method'] == 'POST':
            paths = p['path'].split('/')
            if len(paths) == 2:
                return '作成'
            elif len(paths) > 3:
                if 'action' in paths[3]:
                    m = re.search('.*\((.*)\).*', paths[3])
                    action = t(m.group(1))
                    return action
                else:
                    action = '作成'
                    if 'os-interface' == paths[3]:
                        action = 'のアタッチ'
                    elif 'migrations' == paths[3]:
                        action = 'の強制'
                    # print(paths[3])
                    # print(p['path'])
                    # print("%s%s" % (t(paths[3]), action))
                    return "%s%s" % (t(paths[3]), action)
            elif len(paths) == 3:
                return t(paths[2])
            return p['path']
        elif p['method'] == 'DELETE':
            return '削除'
        else:
            print(p.name)
            return '-'

for p in policies.list_rules():
    if (isinstance(p, policy.DocumentedRuleDefault) and
        not p.deprecated_for_removal and
        not 'deprecated' in p.description.lower()):
        # print('=======')
        # print(p.name)
        # print(p.description)
        # print(p.operations)
        # if len(p.operations) == 1:
        rules.add(p.check_str)
        path = p.operations[0]['path'].split('/')
        if not ps.get(path[1]):
            ps[path[1]] = []
        ps[path[1]].append(p)
        # else:
        #     print(p.name)
        #     for op in p.operations:
        #         print("%s: %s" % (op['method'], op['path']))

if os.path.isfile('nova-policy.xlsx'):
    wb = px.load_workbook(filename='nova-policy.xlsx')
    ws = wb.get_sheet_by_name('Nova')
else:
    wb = px.Workbook()
    ws = wb.create_sheet(title='Nova')

i = 2

for k, v in sorted(ps.items(), key=lambda x: x[0]):
    for p in v:
        # print('---------')
        # print(k, p.name)
        # print(p.description)
        # print(p.deprecated_for_removal)
        # print(p.check_str)
        ws["B%s" % i].value = t(k)
        ws["C%s" % i].value = f(p.operations)
        ws["D%s" % i].value = t(p.check_str)
        ws["E%s" % i].alignment = px.styles.Alignment(wrapText='True')
        ws["E%s" % i].value = p.description
        i += 1

# print('RULES:-------')
# for r in rules:
#     print(r)

wb.save('nova-policy.xlsx')
import openpyxl as px
import re
import os
import sys
import json

output = 'neutron-policy.xlsx'

translation_dict = {
    'create': '作成',
    'delete': '削除',
    'get': '表示',
    'update': '更新',
    'add': '追加',
    'remove': '削除',
    'insert': '挿入',

    'address_scope': 'アドレススコープ',
    'shared': '共有',
    'agent': 'エージェント',
    'agent-loadbalancers': 'ロードバランサーエージェント',
    'auto_allocated_topology': 'トポロジー自動割り当て',
    'dhcp-agents': 'DHCPエージェント',
    'dhcp-network': 'DHCPネットワーク',
    'dhcp-networks': 'DHCPネットワーク一覧',
    'flavor': 'フレーバー',
    'flavor_service_profile': 'フレーバーサービスプロファイル',
    'flavors': 'フレーバー一覧',
    'floatingip': 'フローティングIP',
    'floating_ip_address': 'フローティングIPアドレス',
    'l3-agents': 'L3エージェント',
    'l3-router': 'L3ルーター',
    'l3-routers': 'L3ルーター一覧',
    'loadbalancer-agent': 'ロードバランサーエージェント',
    'loadbalancer-hosting-agent': 'ロードバランサーホストエージェント',
    'loadbalancer-pools': 'ロードバランサープール',
    'lsn': 'LSN',
    'metering_label': 'メータリングラベル',
    'metering_label_rule': 'メータリングラベルルール',
    'network': 'ネットワーク',
    'is_default': 'デフォルト',
    'queue_id': 'キュー',
    'segments': 'セグメント一覧',
    'provider': 'プロバイダ',
    'network_type': 'ネットワークタイプ',
    'physical_network': '物理ネットワーク',
    'segmentation_id': 'セグメンテーション',
    'router': 'ルーター',
    'external': '外部',
    'network_ip_availabilities': 'ネットワークIPのアベイラビリティ一覧',
    'network_ip_availability': 'ネットワークIPのアベイラビリティ',
    'network_profile': 'ネットワークプロファイル',
    'network_profiles': 'ネットワークプロファイル一覧',
    'policy': 'ポリシー',
    'policy_bandwidth_limit_rule': '帯域制限ルールポリシー',
    'policy_dscp_marking_rule': 'DSCPマーキングルールポリシー',
    'policy_minimum_bandwidth_rule': '最低帯域ルールポリシー',
    'policy_profile': 'ポリシープロファイル',
    'policy_profiles': 'ポリシープロファイル一覧',
    'port': 'ポート',
    'allowed_address_pairs': '許可されたアドレスペア',
    'device_owner': 'デバイスオーナ',
    'fixed_ips': '固定IP',
    'mac_address': 'MACアドレス',
    'mac_learning_enabled': 'MACアドレス学習の許可',
    'port_security_enabled': 'ポートセキュリティ',
    'queue_id': 'キュー',
    'binding': 'バインド',
    'host_id': 'ホスト',
    'profile': 'プロファイル',
    'vif_details': 'VIF詳細',
    'vif_type': 'VIFタイプ',
    'qos_queue': 'QOSキュー',
    'rbac_policy': 'RBACポリシー',
    'target_tenant': 'ターゲットテナント',
    'distributed': '分散ルーター',
    'ha': '高可用性ルーター',
    'external_gateway_info': '外部ゲートウェイ情報',
    'enable_snat': 'SNATの許可',
    'external_fixed_ips': '外部固定IP',
    'router_interface': 'ルーターインタフェース',
    'rule': 'ルール',
    'rule_type': 'ルールタイプ',
    'segment': 'セグメント',
    'service_profile': 'サービスプロファイル',
    'service_profiles': 'サービスプロファイル一覧',
    'service_provider': 'サービスプロバイダ',
    'subnet': 'サブネット',
    'segment_id': 'セグメント',
    'service_types': 'サービスタイプ',
    'subnetpool': 'サブネットプール',
    'is_default': 'デフォルト',
    'shared': '共有',
    'subports': 'サブポート',
    'trunk': 'トランク',
    'log': 'ログ',
    'loggable_resources': 'ログ表示可能なリソース一覧',
    'logs': 'ログ一覧',
    'security_group': 'セキュリティグループ',
    'security_groups': 'セキュリティグループ一覧',
    'security_group_rule': 'セキュリティグループルール',
    'security_group_rules': 'セキュリティグループルール一覧',

    'rule:admin_or_owner or rule:shared': '管理者/テナントユーザ (共有は全てのユーザ)',
    'rule:regular_user': '',
    'rule:admin_or_owner': '管理者/テナントユーザ',
    'rule:admin_or_owner or rule:shared or rule:external or rule:context_is_advsvc': '管理者/テナントユーザ/拡張サービス (共有は全てのユーザ)',
    'rule:admin_or_network_owner': '管理者/ネットワークオーナー',
    'rule:admin_or_owner or rule:shared_address_scopes': '管理者/テナントユーザ (共有は除く)',
    'not rule:network_device or rule:context_is_advsvc or rule:admin_or_network_owner': '管理者/テナントユーザ/拡張サービス (ネットワークデバイスを除く)',
    'rule:restrict_wildcard and rule:admin_or_owner': '管理者/テナントユーザ',
    'rule:context_is_advsvc or rule:admin_owner_or_network_owner': '管理者/テナントユーザ/ネットワークオーナー/拡張サービス',
    'rule:restrict_wildcard': '管理者',
    'rule:admin_only': '管理者',
    'rule:context_is_advsvc or rule:admin_or_network_owner': '管理者/ネットワークオーナー/拡張サービス',
    'rule:admin_or_owner or rule:shared_subnetpools': '管理者/テナントユーザ (共有は全てのユーザ)',
    'rule:admin_or_owner or rule:context_is_advsvc': '管理者/テナントユーザ/拡張サービス',
    'rule:admin_only or rule:context_is_advsvc': '管理者/拡張サービス',
    'rule:context_is_advsvc or rule:admin_or_network_owner or rule:shared': '管理者/ネットワークオーナー/拡張サービス (共有は全てのユーザ)',
    'rule:admin_or_data_plane_int': '管理者/データプレーン管理者',
}
def t(k):
    return translation_dict.get(k, k)

class Verb(object):
    def __init__(self, name, check_str):
        super(Verb, self).__init__()
        self.name = name
        self.check_str = check_str

class Attribute(object):
    def __init__(self, name):
        super(Attribute, self).__init__()
        self.name = name
        self.verbs = []


class Resource(object):

    def __init__(self, name):
        super(Resource, self).__init__()
        self.name = name
        self.attributes = {}
        self.resources = {}
        self.verbs = []

    def get_attribute(self, name):
        attribute = self.attributes.get(name, Attribute(name))
        self.attributes[name] = attribute
        return attribute

    def get_resource(self, name):
        resource = self.resources.get(name, Resource(name))
        self.resources[name] = resource
        return resource

class Rules(object):

    def __init__(self):
        super(Rules, self).__init__()
        self.resources = {}

    def get_resource(self, name):
        resource = self.resources.get(name, Resource(name))
        self.resources[name] = resource
        return resource


def parse(raw, check_str):
    rule = {}
    rule['check_str'] = check_str
    m = re.match('(create|update|delete|get|remove|add|insert)_(.*)', raw[0])
    if m:
        rule['verb'] = m.group(1)
        rule['name'] = m.group(2)
        if len(raw) == 2:
            rule['attribute'] = raw[1]
        elif len(raw) == 3:
            rule['sub_resource'] = raw[1]
            rule['attribute'] = raw[2]
        else:
            pass
    else:
        return None
        # print("**********%s" % raw[0])
    return rule

def add_list(rules, raw):
    rule = rules.get_resource(raw['name'])

    raw_verb = raw.get('verb')
    raw_sub_resource = raw.get('sub_resource')
    raw_attribute = raw.get('attribute')
    check_str = raw.get('check_str')
    if raw_sub_resource:
        sub_resource = rule.get_resource(raw_sub_resource)
        sub_resource.get_attribute(raw_attribute).verbs.append(Verb(raw_verb, check_str))
    elif raw_attribute:
        rule.get_attribute(raw_attribute).verbs.append(Verb(raw_verb, check_str))
    else:
        rule.verbs.append(Verb(raw_verb, check_str))

def main(argv):
    rules = Rules()
    try:
        policy_file = argv[1]
    except IndexError as e:
        policy_file = 'etc/policy.json'

    with open(policy_file, 'r') as f:
        # print(f.read())
        policies = json.load(f)

    for k, check_str in policies.items():
        raw = k.split(':')
        raw = parse(raw, check_str)
        if raw:
            add_list(rules, raw)

    if os.path.isfile(output):
        wb = px.load_workbook(filename=output)
        ws = wb.get_sheet_by_name('Neutron')
    else:
        wb = px.Workbook()
        ws = wb.create_sheet(title='Neutron')

    # i = 2

    def fill_cell(name, op, check_str):
        ws["B%s" % fill_cell.i].value = name
        ws["C%s" % fill_cell.i].value = op
        ws["D%s" % fill_cell.i].value = t(check_str)
        fill_cell.i += 1

    fill_cell.i = 2
    checks = set()

    for v in sorted(rules.resources.values(), key=lambda x: x.name):
        # print("'%s': ''," % v.name)
        for verb in sorted(v.verbs, key=lambda x: x.name):
            # print("%s:%s" % (t(v.name), t(verb.name)))
            fill_cell(t(v.name), t(verb.name), verb.check_str)
            checks.add(verb.check_str)
        for a in sorted(v.attributes.values(), key=lambda x: x.name):
            # print("'%s': ''," % a.name)
            for verb in sorted(a.verbs, key=lambda x: x.name):
                # print("%s:%sの%s" % (t(v.name), t(a.name), t(verb.name)))
                fill_cell(t(v.name), "%sの%s" % (t(a.name), t(verb.name)), verb.check_str)
                checks.add(verb.check_str)
        for r in sorted(v.resources.values(), key=lambda x: x.name):
            # print("'%s': ''," % r.name)
            for a in sorted(r.attributes.values(), key=lambda x: x.name):
                # print("'%s': ''," % a.name)
                for verb in sorted(a.verbs, key=lambda x: x.name):
                    # print("%s:%sの%sの%s" % (t(v.name), t(r.name), t(a.name), t(verb.name)))
                    fill_cell(t(v.name), "%sの%sの%s" % (t(r.name), t(a.name), t(verb.name)), verb.check_str)
                    checks.add(verb.check_str)

    for check in checks:
        print("'%s': ''," % check)

    wb.save(output)

if __name__ == '__main__':
    main(sys.argv)