diff --git a/src/spaceone/identity/conf/provider_conf.py b/src/spaceone/identity/conf/provider_conf.py index 3e3327fc..5f681ef8 100644 --- a/src/spaceone/identity/conf/provider_conf.py +++ b/src/spaceone/identity/conf/provider_conf.py @@ -1,6 +1,7 @@ DEFAULT_PROVIDERS = [{ "provider": "aws", "name": "AWS", + "order": 1, "template": { "service_account": { "schema": { @@ -76,6 +77,7 @@ "provider": "google_cloud", "version": "v1", "name": "Google Cloud", + "order": 2, "template": { "service_account": { "schema": { @@ -143,6 +145,7 @@ }, { "provider": "azure", "name": "Azure", + "order": 3, "template": { "service_account": { "schema": { @@ -228,594 +231,4 @@ 'color': '#00BCF2', 'icon': 'https://spaceone-custom-assets.s3.ap-northeast-2.amazonaws.com/console-assets/icons/azure.svg' } -}] - -# }, { -# "provider": "spaceone", -# "name": "SpaceONE", -# "template": { -# "service_account": { -# "schema": { -# "type": "object", -# "properties": { -# "user_id": { -# "title": "User ID", -# "type": "string", -# "minLength": 4 -# } -# }, -# "required": ["user_id"] -# } -# } -# }, -# "capability": { -# "supported_schema": ["spaceone_api_key"] -# }, -# "tags": [ -# { -# 'key': 'color', -# 'value': '#6638B6' -# }, { -# 'key': 'icon', -# 'value': 'https://spaceone-custom-assets.s3.ap-northeast-2.amazonaws.com/console-assets/icons/spaceone.svg' -# } -# ] -# }, { -# "provider": "openstack", -# "name": "OpenStack", -# "template": { -# "service_account": { -# "schema": { -# "type": "object", -# "properties": { -# "username": { -# "title": "Description", -# "type": "string", -# "minLength": 4 -# } -# } -# } -# } -# }, -# "metadata": { -# "view": { -# "layouts": { -# } -# } -# }, -# "capability": { -# "supported_schema": ["openstack_credentials"] -# }, -# "tags": [ -# { -# 'key': 'color', -# 'value': '#EE1142' -# }, { -# 'key': 'icon', -# 'value': 'https://spaceone-custom-assets.s3.ap-northeast-2.amazonaws.com/console-assets/icons/openstack.svg' -# } -# ] -# }, { -# "provider": "alibaba_cloud", -# "name": "Alibaba Cloud", -# "template": { -# "service_account": { -# "schema": { -# "type": "object", -# "properties": { -# "account_id": { -# "title": "Account ID", -# "type": "string", -# "minLength": 4 -# } -# }, -# "required": ["account_id"] -# } -# } -# }, -# "metadata": { -# "view": { -# "layouts": { -# "help:service_account:create": { -# "name": "Creation Help", -# "type": "markdown", -# "options": { -# "markdown": { -# "en": ( -# "# Help for Alibaba Cloud Users\n" -# "## Find Your Alibaba Cloud Account ID\n" -# "Get your Alibaba Cloud Account ID.\n" -# "Individual Account: Alibaba Cloud console > Click your avatar > Account Management Page > Security Settings > **Account ID**\nEnterprise Account: Alibaba Cloud console > Click your avatar > **Enterprise Alias**\n" -# "## Generate Your AccessKey Pair\n" -# "Get your Alibaba Cloud AccessKey ID & AccessKey Secret\n" -# "[Alibaba Cloud AccessKey & AccessSecret](https://www.alibabacloud.com/help/doc-detail/53045.htm?spm=a2c63.p38356.879954.17.6be510df6F9vxS#concept-53045-zh)\n" -# ), -# "ko": ( -# "# 알리바바 클라우드 이용자 가이드\n" -# "## 알리바바 클라우드 계정 아이디(Account ID) 찾기\n" -# "콘솔에서 사용자의 알리바바 클라우드 계정 아이디 확인하기\n" -# "개인 계정: 알리바바 클라우드 콘솔 > 사용자 아바타 클릭 > Account Management 페이지 > Security Settings > **Account ID**\n엔터프라이즈 계정: 알리바바 클라우드 콘솔 > 사용자 아바타 클 > **Enterprise Alias**\n" -# "## 알리바바 클라우드 AccessKey Pair 발급하기\n" -# "콘솔에서 알리바바 클라우드 AccessKey ID & AccessKey Secret 생성하기\n" -# "[Alibaba Cloud AccessKey & AccessKey Secret](https://www.alibabacloud.com/help/doc-detail/53045.htm?spm=a2c63.p38356.879954.17.6be510df6F9vxS#concept-53045-zh)\n" -# ), -# } -# } -# } -# } -# } -# }, -# "capability": { -# "supported_schema": ["alibaba_cloud_access_key_pair"] -# }, -# "tags": [ -# { -# 'key': 'color', -# 'value': '#FF6A00' -# }, { -# 'key': 'icon', -# 'value': 'https://spaceone-custom-assets.s3.ap-northeast-2.amazonaws.com/console-assets/icons/cloud-services/alibaba_cloud/logo.svg' -# }, { -# 'key': 'external_link_template', -# 'value': 'https://homenew-intl.console.aliyun.com/' -# } -# ] -# }, { -# "provider": "oracle_cloud", -# "name": "Oracle Cloud Infrastructure", -# "template": { -# "service_account": { -# "schema": { -# "type": "object", -# "properties": { -# "tenancy_name": { -# "title": "Tenancy Name", -# "type": "string", -# "minLength": 4 -# }, -# "user_name": { -# "title": "User Name", -# "type": "string", -# "minLength": 4 -# } -# }, -# "required": ["tenancy_name", "user_name"] -# } -# } -# }, -# "metadata": { -# "view": { -# "layouts": { -# "help:service_account:create": { -# "name": "Creation Help", -# "type": "markdown", -# "options": { -# "markdown": { -# "en": ( -# "# Getting started with Oracle Cloud Intrastructure\n" -# "## Find Your Tenancy & User OCID\n" -# "[Get your User's OCID and Tenancy's OCID](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm#five)\n" -# "## Generate RSA key pair and Key's Fingerprint\n" -# "[Generate RSA key pair]([https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm#two](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm#two))\n" -# "[Get Key's Fingerprint](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm#four)\n" -# "## Upload the Public Key from the key pair in the Console\n" -# "[Upload Your Public Key](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm#three)\n" -# #R"## Note: It requires to add \n at end of every each line of your private_key string prior to put private key in credentials. ex) -----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0\n...\n..\n" -# "## Note: You must copy and paste the private key, except for the header and footer of the private_key string, before putting it into Credential. The same is true for typing in JSON format; each string is separated by a space.\n" -# ), -# "ko": ( -# "# 오라클 클라우드 이용자 가이드\n" -# "## 오라클 클라우드 테넌시와 유저 OCID 찾기\n" -# "[유저와 테넌시 OCID 정보 확인](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm#five)\n" -# "## RSA 키 페어와 핑거프린트 생성\n" -# "[RSA 키 페어 생성]([https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm#two](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm#two))\n" -# "[핑거프린트 생성](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm#four)\n" -# "## 오라클 클라우드 콘솔에 공개 키 등록\n" -# "[퍼블릭 키 업로드](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm#three)\n" -# "## Note: 개인 키를 Credential에 넣기 전에 private_key 문자열의 헤더와 푸터를 제외하고 복사해서 붙여넣어야 합니다. JSON 형식으로 입력 시에도 동일하며, 각 문자열은 공백으로 구분합니다.\n " -# ), -# } -# } -# } -# } -# } -# }, -# "capability": { -# "supported_schema": ["oci_api_key"] -# }, -# "tags": [ -# { -# 'key': 'color', -# 'value': '#D73A27' -# }, { -# 'key': 'icon', -# 'value': 'https://spaceone-custom-assets.s3.ap-northeast-2.amazonaws.com/console-assets/icons/cloud-services/oci/ic_provider_oracle.svg' -# }, { -# 'key': 'external_link_template', -# 'value': 'https://www.oracle.com/kr/cloud/sign-in.html' -# } -# ] - -aws_access_key = { - "name": "aws_access_key", - "service_type": "secret.credentials", - "schema": { - "required": [ - "aws_access_key_id", - "aws_secret_access_key" - ], - "order": [ - "aws_access_key_id", - "aws_secret_access_key" - ], - "properties": { - "aws_access_key_id": { - "title": "AWS Access Key", - "type": "string", - "format": "password", - "minLength": 4 - }, - "aws_secret_access_key": { - "title": "AWS Secret Key", - "type": "string", - "format": "password", - "minLength": 4 - } - }, - "type": "object" - }, - "labels": ["AWS"], - "tags": {"description": "AWS Access Key"} -} - -aws_assume_role = { - "name": "aws_assume_role", - "service_type": "secret.credentials", - "schema": { - "required": [ - "external_id", - "role_arn" - ], - "order": [ - "external_id", - "role_arn" - ], - "properties": { - "external_id": { - "minLength": 4.0, - "title": "External ID", - "markdown": "[How to use an external ID?](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html)", - "type": "string", - "format": "generate_id" - }, - "role_arn": { - "type": "string", - "minLength": 4.0, - "title": "Role ARN" - } - }, - "type": "object" - }, - "labels": ["AWS", "Assume Role"], - "tags": {"description": "AWS Assume Role"} -} - -google_oauth2_credentials = { - "name": "google_oauth2_credentials", - "service_type": "secret.credentials", - "schema": { - "required": [ - "type", - "project_id", - "private_key_id", - "private_key", - "client_email", - "client_id", - "auth_uri", - "token_uri", - "auth_provider_x509_cert_url", - "client_x509_cert_url" - ], - "properties": { - "client_x509_cert_url": { - "examples": [ - "https://www.googleapis.com/..." - ], - "minLength": 4.0, - "type": "string", - "title": "Client X509 Cert URL" - }, - "auth_uri": { - "title": "Auth URI", - "minLength": 4.0, - "default": "https://acounts.google.com/o/oauth2/auth", - "type": "string" - }, - "private_key_id": { - "examples": [ - "771823abcd..." - ], - "minLength": 4.0, - "type": "string", - "title": "Private Key ID" - }, - "zone": { - "examples": [ - "asia-northeast3" - ], - "type": "string", - "title": "Region", - "minLength": 4.0 - }, - "type": { - "minLength": 4.0, - "type": "string", - "default": "service_account", - "title": "Type" - }, - "client_email": { - "title": "Client Email", - "examples": [ - "api@project-id.iam.gserviceaccount.com(opens in new tab)" - ], - "type": "string", - "minLength": 4.0 - }, - "auth_provider_x509_cert_url": { - "title": "Auth Provider Cert URL", - "minLength": 4.0, - "default": "https://www.googleapis.com/oauth2/v1/certs", - "type": "string" - }, - "private_key": { - "minLength": 4.0, - "examples": [ - "-----BEGIN" - ], - "type": "string", - "title": "Private Key" - }, - "token_uri": { - "title": "Token URI", - "minLength": 4.0, - "default": "https://oauth2.googleapis.com/token", - "type": "string" - }, - "project_id": { - "minLength": 4.0, - "title": "Project ID", - "examples": [ - "project-id" - ], - "type": "string" - }, - "client_id": { - "examples": [ - "10118252....." - ], - "minLength": 4.0, - "type": "string", - "title": "Client ID" - } - }, - "type": "object" - }, - "labels": ["Google Cloud", "GCP", "OAuth2.0"], - "tags": {"description": "Google OAuth2 Credentials"} -} - -azure_client_secret = { - "name": "azure_client_secret", - "service_type": "secret.credentials", - "schema": { - "required": [ - "subscription_id", - "tenant_id", - "client_id", - "client_secret" - ], - "order": [ - "subscription_id", - "tenant_id", - "client_id", - "client_secret" - ], - "properties": { - "client_id": { - "title": "Client ID", - "type": "string", - "minLength": 4 - }, - "client_secret": { - "title": "Client Secret", - "type": "string", - "format": "password", - "minLength": 4 - }, - "tenant_id": { - "title": "Tenant ID", - "type": "string", - "minLength": 4 - }, - "subscription_id": { - "title": "Subscription ID", - "type": "string", - "minLength": 4 - } - }, - "type": "object" - }, - "labels": ["Azure"], - "tags": {"description": "Azure Client Secret"} -} - -spaceone_api_key = { - "name": "spaceone_api_key", - "service_type": "secret.credentials", - "schema": { - "required": [ - "api_key", - "endpoint" - ], - "order": [ - "api_key", - "endpoint" - ], - "properties": { - "api_key": { - "title": "API Key", - "type": "string", - "format": "password", - "minLength": 4 - }, - "endpoint": { - "title": "Identity Service Endpoint", - "type": "string", - "minLength": 4 - } - }, - "type": "object" - }, - "labels": ["SpaceONE"], - "tags": {"description": "SpaceONE API Key"} -} - -alibaba_cloud_access_key_pair = { - "name": "alibaba_cloud_access_key_pair", - "service_type": "secret.credentials", - "schema": { - "required": [ - "ali_access_key_id", - "ali_access_key_secret" - ], - "properties": { - "ali_access_key_id": { - "title": "Alibaba Cloud AccessKey ID", - "type": "string", - "format": "password", - "minLength": 4 - }, - "ali_access_key_secret": { - "title": "Alibaba Cloud AccessKey Secret", - "type": "string", - "format": "password", - "minLength": 4 - } - }, - "type": "object" - }, - "labels": ["Alibaba"], - "tags": {"description": "Alibaba Cloud AccessKey Pair"} -} - -oci_api_key = { - "name": "oci_api_key", - "service_type": "secret.credentials", - "schema": { - "required": [ - "tenancy", - "user", - "key_content", - "fingerprint" - ], - "properties": { - "tenancy": { - "title": "Tenancy's OCID", - "type": "string", - "minLength": 4 - }, - "user": { - "title": "User's OCID", - "type": "string", - "minLength": 4 - }, - "key_content": { - "title": "Private Key Content", - "type": "string", - "minLength": 4 - }, - "fingerprint": { - "title": "Fingerprint", - "type": "string", - "minLength": 4 - } - }, - "type": "object" - }, - "labels": ["Oracle"], - "tags": {"description": "Oracle Cloud Infrastructure Access Configuration"} -} - -openstack_credentials = { - "name": "openstack_credentials", - "service_type": "secret.credentials", - "schema": { - "required": [ - "username", - "password", - "region_name", - "auth_url", - "project_id" - ], - "properties": { - "username": { - "title": "Username", - "type": "string", - "minLength": 1 - }, - "password": { - "title": "Password", - "type": "string", - "minLength": 1 - }, - "region_name": { - "title": "Region", - "type": "string", - "minLength": 1 - }, - "interface": { - "title": "API Interface", - "type": "string", - "minLength": 1, - "examples": ["public"] - }, - "identity_api_version": { - "title": "Identity API Version", - "type": "string", - "minLength": 1, - "examples": ["3"] - }, - "auth_url": { - "title": "Auth URL", - "type": "string", - "minLength": 1 - }, - "user_domain_name": { - "title": "Domain", - "type": "string", - "minLength": 1, - "examples": ["Default"] - }, - "project_id": { - "title": "Project ID", - "type": "string", - "minLength": 1 - }, - "dashboard_url": { - "title": "Dashboard URL", - "type": "string", - "minLength": 1 - }, - "all_projects": { - "title": "All Projects", - "type": "string", - "enum": ["true", "false"], - "minLength": 4, - "examples": ["true"] - } - }, - "type": "object" - }, - "labels": ["OpenStack"], - "tags": {"description": "OpenStack Credentials"} -} +}] \ No newline at end of file diff --git a/src/spaceone/identity/info/provider_info.py b/src/spaceone/identity/info/provider_info.py index 69d5adbb..8731dc99 100644 --- a/src/spaceone/identity/info/provider_info.py +++ b/src/spaceone/identity/info/provider_info.py @@ -10,7 +10,8 @@ def ProviderInfo(provider_vo: Provider, minimal=False): info = { 'provider': provider_vo.provider, - 'name': provider_vo.name + 'name': provider_vo.name, + 'order': provider_vo.order } if not minimal: @@ -19,6 +20,7 @@ def ProviderInfo(provider_vo: Provider, minimal=False): 'metadata': change_struct_type(provider_vo.metadata), 'capability': change_struct_type(provider_vo.capability), 'tags': change_struct_type(provider_vo.tags), + 'domain_id': provider_vo.domain_id, 'created_at': utils.datetime_to_iso8601(provider_vo.created_at) }) diff --git a/src/spaceone/identity/manager/provider_manager.py b/src/spaceone/identity/manager/provider_manager.py index 3f6f012f..72e8259e 100644 --- a/src/spaceone/identity/manager/provider_manager.py +++ b/src/spaceone/identity/manager/provider_manager.py @@ -28,17 +28,20 @@ def _rollback(old_data): _LOGGER.info(f'[update_provider._rollback] Revert Data : {old_data["provider"]}') provider_vo.update(old_data) - provider_vo: Provider = self.get_provider(params['provider']) + provider_vo: Provider = self.get_provider(params['provider'], params['domain_id']) self.transaction.add_rollback(_rollback, provider_vo.to_dict()) return provider_vo.update(params) - def delete_provider(self, provider): - provider_vo: Provider = self.get_provider(provider) + def delete_provider(self, provider, domain_id): + provider_vo: Provider = self.get_provider(provider, domain_id) provider_vo.delete() - def get_provider(self, provider, only=None): - return self.provider_model.get(provider=provider, only=only) + def get_provider(self, provider, domain_id, only=None): + return self.provider_model.get(provider=provider, domain_id=domain_id, only=only) + + def filter_providers(self, **conditions): + return self.provider_model.filter(**conditions) def list_providers(self, query={}): return self.provider_model.query(**query) @@ -46,8 +49,9 @@ def list_providers(self, query={}): def stat_providers(self, query): return self.provider_model.stat(**query) - def create_default_providers(self, installed_providers): + def create_default_providers(self, installed_providers, domain_id): for provider in DEFAULT_PROVIDERS: if provider['provider'] not in installed_providers: _LOGGER.debug(f'Create default provider: {provider["name"]}') + provider['domain_id'] = domain_id self.create_provider(provider) diff --git a/src/spaceone/identity/model/provider_model.py b/src/spaceone/identity/model/provider_model.py index 5a094d30..834b96fb 100644 --- a/src/spaceone/identity/model/provider_model.py +++ b/src/spaceone/identity/model/provider_model.py @@ -3,17 +3,20 @@ class Provider(MongoModel): - provider = StringField(max_length=40, unique=True) + provider = StringField(max_length=40, unique_with='domain_id') name = StringField(max_length=255) + order = IntField(min_value=1, default=10) template = DictField() metadata = DictField() capability = DictField() tags = DictField() + domain_id = StringField(max_length=255) created_at = DateTimeField(auto_now_add=True) meta = { 'updatable_fields': [ 'name', + 'order', 'template', 'metadata', 'capability', @@ -21,10 +24,8 @@ class Provider(MongoModel): ], 'minimal_fields': [ 'provider', - 'name' + 'name', + 'order' ], - 'ordering': ['created_at'], - 'indexes': [ - # 'provider', - ] + 'ordering': ['order', 'name'] } diff --git a/src/spaceone/identity/service/provider_service.py b/src/spaceone/identity/service/provider_service.py index f91bd4f3..b635e1c7 100644 --- a/src/spaceone/identity/service/provider_service.py +++ b/src/spaceone/identity/service/provider_service.py @@ -22,6 +22,7 @@ def create(self, params): params (dict): { 'provider': 'str', 'name': 'str', + 'order': 'int', 'template': 'dict', 'metadata': 'dict', 'capability': 'dict', @@ -45,6 +46,7 @@ def update(self, params): params (dict): { 'provider': 'str', 'name': 'str', + 'order': 'int', 'template': 'dict', 'metadata': 'dict', 'capability': 'dict', @@ -89,12 +91,15 @@ def get(self, params): Returns: provider_vo (object) """ - self._create_default_provider() - return self.provider_mgr.get_provider(params['provider'], params.get('only')) + + domain_id = params['domain_id'] + + self._create_default_provider(domain_id) + return self.provider_mgr.get_provider(params['provider'], domain_id, params.get('only')) @transaction(append_meta={'authorization.scope': 'DOMAIN'}) @check_required(['domain_id']) - @append_query_filter(['provider', 'name']) + @append_query_filter(['provider', 'name', 'domain_id']) @append_keyword_filter(['provider', 'name']) def list(self, params): """ @@ -110,11 +115,15 @@ def list(self, params): results (list): 'list of provider_vo' total_count (int) """ - self._create_default_provider() + + domain_id = params['domain_id'] + + self._create_default_provider(domain_id) return self.provider_mgr.list_providers(params.get('query', {})) @transaction(append_meta={'authorization.scope': 'DOMAIN'}) @check_required(['query', 'domain_id']) + @append_query_filter(['domain_id']) @append_keyword_filter(['provider', 'name']) def stat(self, params): """ @@ -132,10 +141,10 @@ def stat(self, params): query = params.get('query', {}) return self.provider_mgr.stat_providers(query) - @cache.cacheable(key='provider:default:init', expire=300) - def _create_default_provider(self): - provider_vos, total_count = self.provider_mgr.list_providers() + @cache.cacheable(key='provider:{domain_id}:default:init', expire=300) + def _create_default_provider(self, domain_id): + provider_vos = self.provider_mgr.filter_providers(domain_id=domain_id) installed_providers = [provider_vo.provider for provider_vo in provider_vos] - self.provider_mgr.create_default_providers(installed_providers) + self.provider_mgr.create_default_providers(installed_providers, domain_id) return True diff --git a/src/spaceone/identity/service/service_account_service.py b/src/spaceone/identity/service/service_account_service.py index 2a0db6d0..ebf964ed 100644 --- a/src/spaceone/identity/service/service_account_service.py +++ b/src/spaceone/identity/service/service_account_service.py @@ -60,7 +60,7 @@ def create(self, params): else: raise ERROR_INVALID_PARAMETER(key='service_account_type', reason=f'{service_account_type}') - self._check_data(params['data'], params['provider']) + self._check_data(params['data'], params['provider'], domain_id) if 'project_id' in params: params['project'] = self._get_project(params['project_id'], params['domain_id']) @@ -93,7 +93,7 @@ def update(self, params): service_account_vo: ServiceAccount = self.service_account_mgr.get_service_account(service_account_id, domain_id) if 'data' in params: - self._check_data(params['data'], service_account_vo.provider) + self._check_data(params['data'], service_account_vo.provider, domain_id) if project_id: if service_account_vo.service_account_type == 'TRUSTED': @@ -224,9 +224,9 @@ def stat(self, params): return self.service_account_mgr.stat_service_accounts(query) - def _check_data(self, data, provider): + def _check_data(self, data, provider, domain_id): provider_mgr: ProviderManager = self.locator.get_manager('ProviderManager') - provider_vo = provider_mgr.get_provider(provider) + provider_vo = provider_mgr.get_provider(provider, domain_id) schema = provider_vo.template.get('service_account', {}).get('schema') if schema: