From 51a6956ea91b48a6905ebe6cbaa91b04be7a11fa Mon Sep 17 00:00:00 2001 From: Sunandadadi Date: Mon, 15 Jan 2024 16:10:20 -0500 Subject: [PATCH] Revert "marketplace: add logging for user api (PROJQUAY-233) (#2513)" This reverts commit b069cf3b8f291c8211c1799132f9ad29c7b6b0c9. --- .../core-config-setup/config-setup-tool.html | 17 +- .../js/core-config-setup/core-config-setup.js | 36 +- .../pkg/lib/shared/storage_validators.go | 2 +- config-tool/pkg/lib/shared/structs.go | 8 +- config.py | 7 +- data/billing.py | 45 +- ...47693829a0_auto_prune_policy_audit_logs.py | 35 - data/model/entitlements.py | 27 +- data/model/user.py | 7 +- deploy/openshift/quay-py3-app.yaml | 6 +- .../openshift/quay-py3-deploy-template.yaml | 11 +- endpoints/api/billing.py | 81 +- endpoints/api/policy.py | 94 -- endpoints/api/test/test_policy.py | 79 -- endpoints/api/test/test_security.py | 10 +- endpoints/api/test/test_superuser.py | 9 +- initdb.py | 15 - oauth/services/rhsso.py | 13 +- static/css/directives/ui/org-binding.css | 11 - .../directives/billing-management-panel.html | 8 +- static/directives/header-bar.html | 2 +- static/directives/org-binding.html | 53 -- static/directives/plan-manager.html | 13 +- .../directives/repo-view/repo-panel-info.js | 13 +- .../directives/ui/billing-management-panel.js | 29 +- static/js/directives/ui/header-bar.js | 14 + static/js/directives/ui/logs-view.js | 3 - static/js/directives/ui/org-binding.js | 155 ---- static/js/directives/ui/plan-manager.js | 7 +- static/js/directives/ui/usage-chart.js | 14 +- static/js/services/plan-service.js | 49 +- test/test_api_usage.py | 86 +- util/config/schema.py | 9 - util/marketplace.py | 135 +-- util/test/test_marketplace.py | 135 +-- web/cypress/e2e/breadcrumbs.cy.ts | 76 -- web/cypress/e2e/builds.cy.ts | 714 -------------- web/cypress/e2e/theme-switcher.cy.ts | 115 --- web/cypress/fixtures/build-triggers.json | 86 -- web/cypress/fixtures/builds.json | 870 ------------------ web/cypress/fixtures/config.json | 3 +- web/cypress/fixtures/testorg.json | 12 - web/cypress/fixtures/testrepo.json | 16 - web/cypress/test/extra-config.yaml | 1 - web/cypress/test/quay-db-data.txt | 24 +- web/src/App.css | 2 +- web/src/App.tsx | 25 +- web/src/components/Entity.tsx | 88 -- web/src/components/EntityIcon.tsx | 51 + web/src/components/EntitySearch.tsx | 4 +- web/src/components/LinkOrPlainText.tsx | 14 - web/src/components/breadcrumb/Breadcrumb.tsx | 9 +- web/src/components/header/HeaderToolbar.tsx | 196 +--- web/src/components/header/QuayHeader.tsx | 6 - web/src/contexts/ThemeContext.tsx | 77 -- web/src/hooks/UseBuildTriggers.ts | 63 -- web/src/hooks/UseBuilds.ts | 27 - web/src/hooks/UseRepositoryPermissions.ts | 15 +- web/src/libs/utils.ts | 12 +- web/src/resources/BuildResource.ts | 158 ---- web/src/resources/RepositoryResource.ts | 13 +- web/src/resources/UserResource.ts | 24 +- .../OverviewList/RecommendedContent.tsx | 2 +- .../RepositoryDetails/Builds/BuildHistory.tsx | 452 --------- .../Builds/BuildTriggerActions.tsx | 107 --- .../Builds/BuildTriggerDeleteModal.tsx | 69 -- .../Builds/BuildTriggerDescription.tsx | 51 - .../Builds/BuildTriggerToggleModal.tsx | 75 -- .../BuildTriggerViewCredentialsModal.tsx | 93 -- .../Builds/BuildTriggers.tsx | 210 ----- .../BuildTriggersInactiveTriggerRow.tsx | 46 - .../RepositoryDetails/Builds/Builds.tsx | 22 - .../RepositoryDetails/RepositoryDetails.tsx | 12 - .../Settings/Permissions.tsx | 5 +- .../Settings/PermissionsAddPermission.tsx | 8 +- .../SecurityReport/SecurityReportChart.css | 3 - .../SecurityReport/SecurityReportChart.tsx | 3 +- workers/reconciliationworker.py | 93 +- workers/test/test_reconciliationworker.py | 68 +- 79 files changed, 390 insertions(+), 4868 deletions(-) delete mode 100644 data/migrations/versions/8d47693829a0_auto_prune_policy_audit_logs.py delete mode 100644 static/css/directives/ui/org-binding.css delete mode 100644 static/directives/org-binding.html delete mode 100644 static/js/directives/ui/org-binding.js delete mode 100644 web/cypress/e2e/builds.cy.ts delete mode 100644 web/cypress/e2e/theme-switcher.cy.ts delete mode 100644 web/cypress/fixtures/build-triggers.json delete mode 100644 web/cypress/fixtures/builds.json delete mode 100644 web/cypress/fixtures/testorg.json delete mode 100644 web/cypress/fixtures/testrepo.json delete mode 100644 web/src/components/Entity.tsx create mode 100644 web/src/components/EntityIcon.tsx delete mode 100644 web/src/components/LinkOrPlainText.tsx delete mode 100644 web/src/contexts/ThemeContext.tsx delete mode 100644 web/src/hooks/UseBuildTriggers.ts delete mode 100644 web/src/hooks/UseBuilds.ts delete mode 100644 web/src/resources/BuildResource.ts delete mode 100644 web/src/routes/RepositoryDetails/Builds/BuildHistory.tsx delete mode 100644 web/src/routes/RepositoryDetails/Builds/BuildTriggerActions.tsx delete mode 100644 web/src/routes/RepositoryDetails/Builds/BuildTriggerDeleteModal.tsx delete mode 100644 web/src/routes/RepositoryDetails/Builds/BuildTriggerDescription.tsx delete mode 100644 web/src/routes/RepositoryDetails/Builds/BuildTriggerToggleModal.tsx delete mode 100644 web/src/routes/RepositoryDetails/Builds/BuildTriggerViewCredentialsModal.tsx delete mode 100644 web/src/routes/RepositoryDetails/Builds/BuildTriggers.tsx delete mode 100644 web/src/routes/RepositoryDetails/Builds/BuildTriggersInactiveTriggerRow.tsx delete mode 100644 web/src/routes/RepositoryDetails/Builds/Builds.tsx delete mode 100644 web/src/routes/TagDetails/SecurityReport/SecurityReportChart.css diff --git a/config-tool/pkg/lib/editor/js/core-config-setup/config-setup-tool.html b/config-tool/pkg/lib/editor/js/core-config-setup/config-setup-tool.html index 111e964b91..ce4b0a2bd3 100644 --- a/config-tool/pkg/lib/editor/js/core-config-setup/config-setup-tool.html +++ b/config-tool/pkg/lib/editor/js/core-config-setup/config-setup-tool.html @@ -40,7 +40,7 @@
- Name of registry to be displayed in the Contact Page. + Name of registry to be displayed in the Contact Page.
@@ -72,7 +72,7 @@ is displayed. - + @@ -215,7 +215,7 @@ - + @@ -459,7 +459,6 @@ - @@ -746,7 +745,7 @@ Security Scanner PSK: -
Clair Pre-Shared Key. Make sure to include this value in your Clair config. @@ -1736,7 +1735,7 @@

Callback URLs for this service:

- Users included in this list will be given elevated access to Quay. + Users included in this list will be given elevated access to Quay.
@@ -1996,14 +1995,14 @@
- - + +
Config Sent to Operator
- +
diff --git a/config-tool/pkg/lib/editor/js/core-config-setup/core-config-setup.js b/config-tool/pkg/lib/editor/js/core-config-setup/core-config-setup.js index efeb0667c2..6f3c8c6338 100644 --- a/config-tool/pkg/lib/editor/js/core-config-setup/core-config-setup.js +++ b/config-tool/pkg/lib/editor/js/core-config-setup/core-config-setup.js @@ -121,16 +121,6 @@ angular.module("quay-config") {'name': 'storage_path', 'title': 'Storage Directory', 'placeholder': '/path/inside/bucket', 'kind': 'text'} ], - 'IBMCloudStorage': [ - {'name': 'hostname', 'title': 'IBM Cloud Storage Hostname', 'placeholder': 'storage hostname', 'kind': 'text'}, - {'name': 'port', 'title': 'Custom Port (optional)', 'placeholder': '443', 'kind': 'text', 'pattern': '^[0-9]+$', 'optional': true}, - {'name': 'is_secure', 'title': 'Is Secure', 'placeholder': 'Require SSL', 'kind': 'bool'}, - {'name': 'access_key', 'title': 'Access Key', 'placeholder': 'accesskeyhere', 'kind': 'text'}, - {'name': 'secret_key', 'title': 'Secret Key', 'placeholder': 'secretkeyhere', 'kind': 'text'}, - {'name': 'bucket_name', 'title': 'Bucket Name', 'placeholder': 'my-cool-bucket', 'kind': 'text'}, - {'name': 'storage_path', 'title': 'Storage Directory', 'placeholder': '/path/inside/bucket', 'kind': 'text'} - ], - 'SwiftStorage': [ {'name': 'auth_version', 'title': 'Swift Auth Version', 'kind': 'option', 'values': [1, 2, 3]}, {'name': 'auth_url', 'title': 'Swift Auth URL', 'placeholder': 'http://swiftdomain/auth/v1.0', 'kind': 'text'}, @@ -329,10 +319,10 @@ angular.module("quay-config") delete $scope.config["DB_CONNECTION_ARGS"]["ssl"]; $scope.config["DB_CONNECTION_ARGS"]["sslrootcert"] = "conf/stack/database.pem"; $scope.config["DB_CONNECTION_ARGS"]["sslmode"] = "verify-full" - } else if + } else if ($scope.certs["database.pem"] && $scope.config["DB_URI"].startsWith("mysql")){ delete $scope.config["DB_CONNECTION_ARGS"]["sslrootcert"]; - delete $scope.config["DB_CONNECTION_ARGS"]["sslmode"]; + delete $scope.config["DB_CONNECTION_ARGS"]["sslmode"]; $scope.config["DB_CONNECTION_ARGS"]["ssl"] = {} $scope.config["DB_CONNECTION_ARGS"]["ssl"]["ca"] = "conf/stack/database.pem"; } @@ -375,7 +365,7 @@ angular.module("quay-config") } $scope.checkValidateAndSave = function() { - + if ($scope.configform.$valid) { saveStorageConfig(); $scope.validateAndSave(); @@ -385,7 +375,7 @@ angular.module("quay-config") var query = $.find(".ng-invalid"); console.log(query) - if (query && query.length) { + if (query && query.length) { query[1].scrollIntoView(); query[1].focus(); } @@ -628,7 +618,7 @@ angular.module("quay-config") $scope.mapped['database'] = {} $scope.mapped['database'] = parseDbUri(getKey(config, "DB_URI")) console.log($scope.mapped['database']) - + }; var tlsSetter = function(value) { @@ -703,7 +693,7 @@ angular.module("quay-config") } $scope.config['DB_URI'] = uri - + }; var logsModelSelector = function(keyname) { @@ -1114,7 +1104,7 @@ angular.module("quay-config") } } $scope.$watch("certs", checkHasFile, true); - + $scope.onFileSelect = function(files) { if (files.length < 1) { $scope.hasFile = false; @@ -1156,9 +1146,9 @@ angular.module("quay-config") $scope.uploadProgress = null; }); }; - - - + + + }; } @@ -1405,7 +1395,7 @@ angular.module("quay-config") }; return directiveDefinitionObject; }) - + .directive('configStringField', function () { var directiveDefinitionObject = { priority: 0, @@ -1552,7 +1542,7 @@ angular.module("quay-config") const c = new X509(); c.readCertPEM(atob(contents)); const current = new Date(); - // This function returns a bad string, so we have to do some extra formatting to normalize it. + // This function returns a bad string, so we have to do some extra formatting to normalize it. let originalDateString = "20"+c.getNotAfter() let formattedDateString = originalDateString.replace( /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/, @@ -1595,7 +1585,7 @@ angular.module("quay-config") cn.push(attr.value) } }) - return cn + return cn } $scope.deleteCert = function (certPath) { diff --git a/config-tool/pkg/lib/shared/storage_validators.go b/config-tool/pkg/lib/shared/storage_validators.go index 63a0c2085b..b2eaf126fc 100644 --- a/config-tool/pkg/lib/shared/storage_validators.go +++ b/config-tool/pkg/lib/shared/storage_validators.go @@ -34,7 +34,7 @@ func ValidateStorage(opts Options, storageName string, storageType string, args switch storageType { case "LocalStorage": return true, []ValidationError{} - case "RHOCSStorage", "RadosGWStorage", "IBMCloudStorage": + case "RHOCSStorage", "RadosGWStorage": // Check access key if ok, err := ValidateRequiredString(args.AccessKey, "DISTRIBUTED_STORAGE_CONFIG."+storageName+".access_key", fgName); !ok { diff --git a/config-tool/pkg/lib/shared/structs.go b/config-tool/pkg/lib/shared/structs.go index ea4c3ccd92..812f29457b 100644 --- a/config-tool/pkg/lib/shared/structs.go +++ b/config-tool/pkg/lib/shared/structs.go @@ -19,7 +19,7 @@ func (ve ValidationError) String() string { // DistributedStorageArgs type DistributedStorageArgs struct { - // Args for RHOCSStorage, RadosGWStorage, IBMCloudStorage + // Args for RHOCSStorage, RadosGWStorage Hostname string `default:"" validate:"" json:"hostname,omitempty" yaml:"hostname,omitempty"` Port int `default:"" validate:"" json:"port,omitempty" yaml:"port,omitempty"` IsSecure bool `default:"" validate:"" json:"is_secure" yaml:"is_secure"` @@ -53,7 +53,7 @@ type DistributedStorageArgs struct { // Args for CloudFlare CloudflareDomain string `default:"" validate:"" json:"cloudflare_domain,omitempty" yaml:"cloudflare_domain,omitempty"` // Args for MultiCDNStorage - DefaultProvider string `default:"" validate:"" json:"default_provider,omitempty" yaml:"default_provider,omitempty"` - Providers map[string]interface{} `default:"" validate:"" json:"providers,omitempty" yaml:"providers,omitempty"` - StorageConfig map[string]interface{} `default:"" validate:"" json:"storage_config,omitempty" yaml:"storage_config,omitempty"` + DefaultProvider string `default:"" validate:"" json:"default_provider,omitempty" yaml:"default_provider,omitempty"` + Providers map[string]interface{} `default:"" validate:"" json:"providers,omitempty" yaml:"providers,omitempty"` + StorageConfig map[string]interface{} `default:"" validate:"" json:"storage_config,omitempty" yaml:"storage_config,omitempty"` } diff --git a/config.py b/config.py index c38fbcaa75..565b6b352a 100644 --- a/config.py +++ b/config.py @@ -70,6 +70,7 @@ def frontend_visible_config(config_dict): # Configuration that should not be changed by end users class ImmutableConfig(object): + # Requests based HTTP client with a large request pool HTTPCLIENT = build_requests_session() @@ -820,9 +821,6 @@ def create_transaction(db): # Feature Flag: Enables repository settings in the beta UI Environment FEATURE_UI_V2_REPO_SETTINGS = False - # Feature Flag: Enables repository builds in the beta UI Environment - FEATURE_UI_V2_BUILDS = False - # User feedback form for UI-V2 UI_V2_FEEDBACK_FORM = "https://7qdvkuo9rkj.typeform.com/to/XH5YE79P" @@ -863,6 +861,3 @@ def create_transaction(db): FEATURE_UI_DELAY_AFTER_WRITE = False UI_DELAY_AFTER_WRITE_SECONDS = 3 - - # whitelist for ROBOTS_DISALLOW to grant access/usage for mirroring - ROBOTS_WHITELIST: Optional[List[str]] = [] diff --git a/data/billing.py b/data/billing.py index 0c31e28214..c962a644f5 100644 --- a/data/billing.py +++ b/data/billing.py @@ -1,6 +1,5 @@ import random import string -import sys from calendar import timegm from datetime import datetime, timedelta from typing import Any, Dict @@ -224,7 +223,6 @@ "privateRepos": 5, "stripeId": "personal-2018", "rh_sku": "MW00584MO", - "sku_billing": False, "audience": "Individuals", "bus_features": False, "deprecated": False, @@ -237,7 +235,6 @@ "price": 3000, "privateRepos": 10, "rh_sku": "MW00585MO", - "sku_billing": False, "stripeId": "bus-micro-2018", "audience": "For startups", "bus_features": True, @@ -251,7 +248,6 @@ "price": 6000, "privateRepos": 20, "rh_sku": "MW00586MO", - "sku_billing": False, "stripeId": "bus-small-2018", "audience": "For small businesses", "bus_features": True, @@ -265,7 +261,6 @@ "price": 12500, "privateRepos": 50, "rh_sku": "MW00587MO", - "sku_billing": False, "stripeId": "bus-medium-2018", "audience": "For normal businesses", "bus_features": True, @@ -279,7 +274,6 @@ "price": 25000, "privateRepos": 125, "rh_sku": "MW00588MO", - "sku_billing": False, "stripeId": "bus-large-2018", "audience": "For large businesses", "bus_features": True, @@ -293,7 +287,6 @@ "price": 45000, "privateRepos": 250, "rh_sku": "MW00589MO", - "billing_enabled": False, "stripeId": "bus-xlarge-2018", "audience": "For extra large businesses", "bus_features": True, @@ -307,7 +300,6 @@ "price": 85000, "privateRepos": 500, "rh_sku": "MW00590MO", - "billing_enabled": False, "stripeId": "bus-500-2018", "audience": "For huge business", "bus_features": True, @@ -321,7 +313,6 @@ "price": 160000, "privateRepos": 1000, "rh_sku": "MW00591MO", - "sku_billing": False, "stripeId": "bus-1000-2018", "audience": "For the SaaS savvy enterprise", "bus_features": True, @@ -335,7 +326,6 @@ "price": 310000, "privateRepos": 2000, "rh_sku": "MW00592MO", - "sku_billing": False, "stripeId": "bus-2000-2018", "audience": "For the SaaS savvy big enterprise", "bus_features": True, @@ -356,33 +346,9 @@ "superseded_by": None, "plans_page_hidden": False, }, - { - "title": "premium", - "privateRepos": 100, - "stripeId": "not_a_stripe_plan", - "rh_sku": "MW02701", - "sku_billing": True, - "plans_page_hidden": True, - }, - { - "title": "selfsupport", - "privateRepos": sys.maxsize, - "stripeId": "not_a_stripe_plan", - "rh_sku": "MW02702", - "sku_billing": True, - "plans_page_hidden": True, - }, ] -RH_SKUS = [ - plan["rh_sku"] for plan in PLANS if plan.get("rh_sku") is not None and plan.get("sku_billing") -] - -RECONCILER_SKUS = [ - plan["rh_sku"] - for plan in PLANS - if plan.get("rh_sku") is not None and not plan.get("sku_billing") -] +RH_SKUS = [plan["rh_sku"] for plan in PLANS if plan.get("rh_sku") is not None] def get_plan(plan_id): @@ -400,8 +366,6 @@ def get_plan_using_rh_sku(sku): """ Returns the plan with given sku or None if none. """ - if sku is None: - return None for plan in PLANS: if plan.get("rh_sku") == sku: return plan @@ -411,13 +375,6 @@ def get_plan_using_rh_sku(sku): class FakeStripe(object): ACTIVE_CUSTOMERS: Dict[str, Any] = {} - class error(object): - class InvalidRequestException(Exception): - pass - - class APIConnectionError(Exception): - pass - class FakeSubscription(AttrDict): @classmethod def build(cls, data, customer): diff --git a/data/migrations/versions/8d47693829a0_auto_prune_policy_audit_logs.py b/data/migrations/versions/8d47693829a0_auto_prune_policy_audit_logs.py deleted file mode 100644 index 21c60e3f44..0000000000 --- a/data/migrations/versions/8d47693829a0_auto_prune_policy_audit_logs.py +++ /dev/null @@ -1,35 +0,0 @@ -"""auto prune policy audit logs - -Revision ID: 8d47693829a0 -Revises: 2062bbd5ef0e -Create Date: 2023-10-23 14:34:38.908240 - -""" - -# revision identifiers, used by Alembic. -revision = "8d47693829a0" -down_revision = "2062bbd5ef0e" - -import sqlalchemy as sa - - -def upgrade(op, tables, tester): - op.bulk_insert( - tables.logentrykind, - [ - {"name": "create_namespace_autoprune_policy"}, - {"name": "update_namespace_autoprune_policy"}, - {"name": "delete_namespace_autoprune_policy"}, - ], - ) - - -def downgrade(op, tables, tester): - op.execute( - tables.logentrykind.delete().where( - tables.logentrykind.c.name - == op.inline_literal("create_namespace_autoprune_policy") | tables.logentrykind.c.name - == op.inline_literal("update_namespace_autoprune_policy") | tables.logentrykind.c.name - == op.inline_literal("delete_namespace_autoprune_policy") - ) - ) diff --git a/data/model/entitlements.py b/data/model/entitlements.py index a08c1a2727..aa09f1f4f9 100644 --- a/data/model/entitlements.py +++ b/data/model/entitlements.py @@ -6,7 +6,7 @@ logger = logging.getLogger(__name__) -def get_web_customer_id(user_id): +def get_ebs_account_number(user_id): try: query = RedHatSubscriptions.get(RedHatSubscriptions.user_id == user_id).account_number return query @@ -14,29 +14,8 @@ def get_web_customer_id(user_id): return None -def save_web_customer_id(user, web_customer_id): +def save_ebs_account_number(user, ebsAccountNumber): try: - return RedHatSubscriptions.create(user_id=user.id, account_number=web_customer_id) + return RedHatSubscriptions.create(user_id=user.id, account_number=ebsAccountNumber) except model.DataModelException as ex: logger.error("Problem saving account number for %s: %s", user.username, ex) - - -def update_web_customer_id(user, web_customer_id): - try: - query = RedHatSubscriptions.update( - {RedHatSubscriptions.account_number: web_customer_id} - ).where(RedHatSubscriptions.user_id == user.id) - query.execute() - except model.DataModelException as ex: - logger.error("Problem updating customer id for %s: %s", user.username, ex) - - -def remove_web_customer_id(user, web_customer_id): - try: - customer_id = RedHatSubscriptions.get( - RedHatSubscriptions.user_id == user.id, - RedHatSubscriptions.account_number == web_customer_id, - ) - return customer_id.delete_instance() - except model.DataModelException as ex: - logger.error("Problem removing customer id for %s: %s", user.username, ex) diff --git a/data/model/user.py b/data/model/user.py index 2fb80ab758..beeb7e3692 100644 --- a/data/model/user.py +++ b/data/model/user.py @@ -328,7 +328,7 @@ def update_enabled(user, set_enabled): def create_robot(robot_shortname, parent, description="", unstructured_metadata=None, token=None): (username_valid, username_issue) = validate_username(robot_shortname) if config.app_config.get("ROBOTS_DISALLOW", False): - msg = "Robot accounts have been disabled. Please contact your administrator." + msg = "Robot accounts have beeen disabled. Please contact your administrator." raise InvalidRobotException(msg) if not username_valid: @@ -443,9 +443,8 @@ def get_matching_robots(name_prefix, username, limit=10): def verify_robot(robot_username, password): if config.app_config.get("ROBOTS_DISALLOW", False): - if not robot_username in config.app_config.get("ROBOTS_WHITELIST", []): - msg = "Robot account have been disabled. Please contact your administrator." - raise InvalidRobotException(msg) + msg = "Robot accounts have been disabled. Please contact your administrator." + raise InvalidRobotException(msg) try: password.encode("ascii") except UnicodeEncodeError: diff --git a/deploy/openshift/quay-py3-app.yaml b/deploy/openshift/quay-py3-app.yaml index 0a1d14b588..8b0d819bd6 100644 --- a/deploy/openshift/quay-py3-app.yaml +++ b/deploy/openshift/quay-py3-app.yaml @@ -299,8 +299,6 @@ objects: value: ${DB_CONNECTION_POOLING} - name: WORKER_COUNT_WEB value: ${WORKER_COUNT_WEB} - - name: WORKER_COUNT_REGISTRY - value: ${WORKER_COUNT_REGISTRY} parameters: - name: NAME value: "quay-py3" @@ -508,6 +506,4 @@ parameters: - name: IGNORE_VALIDATION value: "false" - name: WORKER_COUNT_WEB - value: "4" - - name: WORKER_COUNT_REGISTRY - value: "28" + value: "8" diff --git a/deploy/openshift/quay-py3-deploy-template.yaml b/deploy/openshift/quay-py3-deploy-template.yaml index ee1058da25..01ff763f8c 100644 --- a/deploy/openshift/quay-py3-deploy-template.yaml +++ b/deploy/openshift/quay-py3-deploy-template.yaml @@ -235,8 +235,7 @@ objects: - /quay-registry/quay-entrypoint.sh - ${{QUAY_ENTRYPOINT}} ports: - - containerPort: ${{LOADBALANCER_SERVICE_TARGET_PORT}} - - containerPort: ${{LOADBALANCER_SERVICE_PROXY_TARGET_PORT}} + - containerPort: 8443 volumeMounts: - name: configvolume mountPath: /conf/stack @@ -296,10 +295,6 @@ objects: value: ${QUAY_WORKER_CONNECTION_COUNT_REGISTRY} - name: DB_CONNECTION_POOLING value: ${DB_CONNECTION_POOLING} - - name: WORKER_COUNT_WEB - value: ${WORKER_COUNT_WEB} - - name: WORKER_COUNT_REGISTRY - value: ${WORKER_COUNT_REGISTRY} parameters: - name: NAME value: "quay-py3" @@ -506,7 +501,3 @@ parameters: value: "200" - name: IGNORE_VALIDATION value: "false" - - name: WORKER_COUNT_WEB - value: "4" - - name: WORKER_COUNT_REGISTRY - value: "28" diff --git a/endpoints/api/billing.py b/endpoints/api/billing.py index 012cf87add..056da32c7b 100644 --- a/endpoints/api/billing.py +++ b/endpoints/api/billing.py @@ -955,11 +955,9 @@ def get(self, orgname): if query: subscriptions = list(query.dicts()) for subscription in subscriptions: - subscription_sku = marketplace_subscriptions.get_subscription_sku( + subscription["sku"] = marketplace_subscriptions.get_subscription_sku( subscription["subscription_id"] ) - subscription["sku"] = subscription_sku - subscription["metadata"] = get_plan_using_rh_sku(subscription_sku) return subscriptions else: return [] @@ -973,71 +971,35 @@ def post(self, orgname): """ permission = AdministerOrganizationPermission(orgname) request_data = request.get_json() - organization = model.organization.get_organization(orgname) - subscriptions = request_data["subscriptions"] + subscription_id = request_data["subscription_id"] if permission.can(): - for subscription in subscriptions: - subscription_id = subscription.get("subscription_id") - if subscription_id is None: - break - user = get_authenticated_user() - account_number = marketplace_users.get_account_number(user) - subscriptions = marketplace_subscriptions.get_list_of_subscriptions(account_number) - - if subscriptions is None: - abort(401, message="no valid subscriptions present") - - user_subscription_ids = [int(subscription["id"]) for subscription in subscriptions] - if int(subscription_id) in user_subscription_ids: - try: - model.organization_skus.bind_subscription_to_org( - user_id=user.id, subscription_id=subscription_id, org_id=organization.id - ) - except model.OrgSubscriptionBindingAlreadyExists: - abort(400, message="subscription is already bound to an org") - else: - abort( - 401, - message=f"subscription {subscription_id} does not belong to {user.username}", - ) + organization = model.organization.get_organization(orgname) + user = get_authenticated_user() + account_number = marketplace_users.get_account_number(user) + subscriptions = marketplace_subscriptions.get_list_of_subscriptions(account_number) - return "Okay", 201 - - abort(401) + if subscriptions is None: + abort(401, message="no valid subscriptions present") + user_subscription_ids = [int(subscription["id"]) for subscription in subscriptions] + if int(subscription_id) in user_subscription_ids: + try: + model.organization_skus.bind_subscription_to_org( + user_id=user.id, subscription_id=subscription_id, org_id=organization.id + ) + return "Okay", 201 + except model.OrgSubscriptionBindingAlreadyExists: + abort(400, message="subscription is already bound to an org") + else: + abort(401, message=f"subscription does not belong to {user.username}") -@resource("/v1/organization//marketplace/batchremove") -@path_param("orgname", "The name of the organization") -@show_if(features.BILLING) -class OrganizationRhSkuBatchRemoval(ApiResource): - @require_scope(scopes.ORG_ADMIN) - @nickname("batchRemoveSku") - def post(self, orgname): - """ - Batch remove skus from org - """ - permission = AdministerOrganizationPermission(orgname) - request_data = request.get_json() - subscriptions = request_data["subscriptions"] - if permission.can(): - try: - organization = model.organization.get_organization(orgname) - except InvalidOrganizationException: - return ("Organization not valid", 400) - for subscription in subscriptions: - subscription_id = int(subscription.get("subscription_id")) - if subscription_id is None: - break - model.organization_skus.remove_subscription_from_org( - organization.id, subscription_id - ) - return ("Deleted", 204) abort(401) @resource("/v1/organization//marketplace/") @path_param("orgname", "The name of the organization") @path_param("subscription_id", "Marketplace subscription id") +@related_user_resource(UserPlan) @show_if(features.BILLING) class OrganizationRhSkuSubscriptionField(ApiResource): """ @@ -1045,7 +1007,6 @@ class OrganizationRhSkuSubscriptionField(ApiResource): """ @require_scope(scopes.ORG_ADMIN) - @nickname("removeSkuFromOrg") def delete(self, orgname, subscription_id): """ Remove sku from an org @@ -1093,6 +1054,4 @@ def get(self): else: subscription["assigned_to_org"] = None - subscription["metadata"] = get_plan_using_rh_sku(subscription["sku"]) - return user_subscriptions diff --git a/endpoints/api/policy.py b/endpoints/api/policy.py index cbfecf0b8c..6b04556288 100644 --- a/endpoints/api/policy.py +++ b/endpoints/api/policy.py @@ -10,8 +10,6 @@ from endpoints.api import ( ApiResource, allow_if_superuser, - log_action, - nickname, path_param, request_error, require_scope, @@ -52,11 +50,7 @@ class OrgAutoPrunePolicies(ApiResource): } @require_scope(scopes.ORG_ADMIN) - @nickname("listOrganizationAutoPrunePolicies") def get(self, orgname): - """ - Lists the auto-prune policies for the organization - """ permission = AdministerOrganizationPermission(orgname) if not permission.can() and not allow_if_superuser(): raise Unauthorized() @@ -67,11 +61,7 @@ def get(self, orgname): @require_scope(scopes.ORG_ADMIN) @validate_json_request("AutoPrunePolicyConfig") - @nickname("createOrganizationAutoPrunePolicy") def post(self, orgname): - """ - Creates an auto-prune policy for the organization - """ permission = AdministerOrganizationPermission(orgname) if not permission.can() and not allow_if_superuser(): raise Unauthorized() @@ -99,16 +89,6 @@ def post(self, orgname): except model.NamespaceAutoPrunePolicyAlreadyExists as ex: request_error(ex) - log_action( - "create_namespace_autoprune_policy", - orgname, - { - "method": policy_config["method"], - "value": policy_config["value"], - "namespace": orgname, - }, - ) - return {"uuid": policy.uuid}, 201 @@ -140,11 +120,7 @@ class OrgAutoPrunePolicy(ApiResource): } @require_scope(scopes.ORG_ADMIN) - @nickname("getOrganizationAutoPrunePolicy") def get(self, orgname, policy_uuid): - """ - Fetches the auto-prune policy for the organization - """ permission = AdministerOrganizationPermission(orgname) if not permission.can() and not allow_if_superuser(): raise Unauthorized() @@ -157,11 +133,7 @@ def get(self, orgname, policy_uuid): @require_scope(scopes.ORG_ADMIN) @validate_json_request("AutoPrunePolicyConfig") - @nickname("updateOrganizationAutoPrunePolicy") def put(self, orgname, policy_uuid): - """ - Updates the auto-prune policy for the organization - """ permission = AdministerOrganizationPermission(orgname) if not permission.can() and not allow_if_superuser(): raise Unauthorized() @@ -191,24 +163,10 @@ def put(self, orgname, policy_uuid): except model.NamespaceAutoPrunePolicyDoesNotExist as ex: raise NotFound() - log_action( - "update_namespace_autoprune_policy", - orgname, - { - "method": policy_config["method"], - "value": policy_config["value"], - "namespace": orgname, - }, - ) - return {"uuid": policy_uuid}, 204 @require_scope(scopes.ORG_ADMIN) - @nickname("deleteOrganizationAutoPrunePolicy") def delete(self, orgname, policy_uuid): - """ - Deletes the auto-prune policy for the organization - """ permission = AdministerOrganizationPermission(orgname) if not permission.can() and not allow_if_superuser(): raise Unauthorized() @@ -222,12 +180,6 @@ def delete(self, orgname, policy_uuid): except model.NamespaceAutoPrunePolicyDoesNotExist as ex: raise NotFound() - log_action( - "delete_namespace_autoprune_policy", - orgname, - {"policy_uuid": policy_uuid, "namespace": orgname}, - ) - return {"uuid": policy_uuid}, 200 @@ -257,11 +209,7 @@ class UserAutoPrunePolicies(ApiResource): } @require_user_admin() - @nickname("listUserAutoPrunePolicies") def get(self): - """ - Lists the auto-prune policies for the currently logged in user - """ user = get_authenticated_user() policies = model.autoprune.get_namespace_autoprune_policies_by_orgname(user.username) @@ -270,11 +218,7 @@ def get(self): @require_user_admin() @validate_json_request("AutoPrunePolicyConfig") - @nickname("createUserAutoPrunePolicy") def post(self): - """ - Creates the auto-prune policy for the currently logged in user - """ user = get_authenticated_user() app_data = request.get_json() @@ -299,16 +243,6 @@ def post(self): except model.NamespaceAutoPrunePolicyAlreadyExists as ex: request_error(ex) - log_action( - "create_namespace_autoprune_policy", - user.username, - { - "method": policy_config["method"], - "value": policy_config["value"], - "namespace": user.username, - }, - ) - return {"uuid": policy.uuid}, 201 @@ -339,11 +273,7 @@ class UserAutoPrunePolicy(ApiResource): } @require_user_admin() - @nickname("getUserAutoPrunePolicy") def get(self, policy_uuid): - """ - Fetches the auto-prune policy for the currently logged in user - """ user = get_authenticated_user() policy = model.autoprune.get_namespace_autoprune_policy(user.username, policy_uuid) @@ -354,11 +284,7 @@ def get(self, policy_uuid): @require_user_admin() @validate_json_request("AutoPrunePolicyConfig") - @nickname("updateUserAutoPrunePolicy") def put(self, policy_uuid): - """ - Updates the auto-prune policy for the currently logged in user - """ user = get_authenticated_user() app_data = request.get_json() @@ -386,24 +312,10 @@ def put(self, policy_uuid): except model.NamespaceAutoPrunePolicyDoesNotExist as ex: raise NotFound() - log_action( - "update_namespace_autoprune_policy", - user.username, - { - "method": policy_config["method"], - "value": policy_config["value"], - "namespace": user.username, - }, - ) - return {"uuid": policy_uuid}, 204 @require_user_admin() - @nickname("deleteUserAutoPrunePolicy") def delete(self, policy_uuid): - """ - Deletes the auto-prune policy for the currently logged in user - """ user = get_authenticated_user() try: @@ -415,10 +327,4 @@ def delete(self, policy_uuid): except model.NamespaceAutoPrunePolicyDoesNotExist as ex: raise NotFound() - log_action( - "delete_namespace_autoprune_policy", - user.username, - {"policy_uuid": policy_uuid, "namespace": user.username}, - ) - return {"uuid": policy_uuid}, 200 diff --git a/endpoints/api/test/test_policy.py b/endpoints/api/test/test_policy.py index 6ac37fa022..df481e9b66 100644 --- a/endpoints/api/test/test_policy.py +++ b/endpoints/api/test/test_policy.py @@ -1,9 +1,6 @@ -import json - import pytest from data import database, model -from data.model.log import get_latest_logs_query, get_log_entry_kinds from endpoints.api.policy import ( OrgAutoPrunePolicies, OrgAutoPrunePolicy, @@ -41,19 +38,6 @@ def test_create_org_policy(initialized_db, app): org = model.organization.get_organization("sellnsmall") assert model.autoprune.namespace_has_autoprune_task(org.id) - # Check audit log was created - logs = list(get_latest_logs_query(performer="devtable", namespace="sellnsmall")) - log_kinds = get_log_entry_kinds() - log = None - for l in logs: - if l.kind == log_kinds["create_namespace_autoprune_policy"]: - log = l - break - assert log is not None - assert json.loads(log.metadata_json)["method"] == "creation_date" - assert json.loads(log.metadata_json)["value"] == "2w" - assert json.loads(log.metadata_json)["namespace"] == "sellnsmall" - def test_create_org_policy_already_existing(initialized_db, app): with client_with_identity("devtable", app) as cl: @@ -117,19 +101,6 @@ def test_update_org_policy(initialized_db, app): assert get_response["method"] == "creation_date" assert get_response["value"] == "2w" - # Check audit log was created - logs = list(get_latest_logs_query(performer="devtable", namespace="buynlarge")) - log_kinds = get_log_entry_kinds() - log = None - for l in logs: - if l.kind == log_kinds["update_namespace_autoprune_policy"]: - log = l - break - assert log is not None - assert json.loads(log.metadata_json)["method"] == "creation_date" - assert json.loads(log.metadata_json)["value"] == "2w" - assert json.loads(log.metadata_json)["namespace"] == "buynlarge" - def test_update_org_policy_nonexistent_policy(initialized_db, app): with client_with_identity("devtable", app) as cl: @@ -163,18 +134,6 @@ def test_delete_org_policy(initialized_db, app): expected_code=404, ) - # Check audit log was created - logs = list(get_latest_logs_query(performer="devtable", namespace="buynlarge")) - log_kinds = get_log_entry_kinds() - log = None - for l in logs: - if l.kind == log_kinds["delete_namespace_autoprune_policy"]: - log = l - break - assert log is not None - assert json.loads(log.metadata_json)["policy_uuid"] == policy_uuid - assert json.loads(log.metadata_json)["namespace"] == "buynlarge" - def test_delete_org_policy_nonexistent_policy(initialized_db, app): with client_with_identity("devtable", app) as cl: @@ -213,19 +172,6 @@ def test_create_user_policy(initialized_db, app): org = model.user.get_user("freshuser") assert model.autoprune.namespace_has_autoprune_task(org.id) - # Check audit log was created - logs = list(get_latest_logs_query(performer="freshuser", namespace="freshuser")) - log_kinds = get_log_entry_kinds() - log = None - for l in logs: - if l.kind == log_kinds["create_namespace_autoprune_policy"]: - log = l - break - assert log is not None - assert json.loads(log.metadata_json)["method"] == "creation_date" - assert json.loads(log.metadata_json)["value"] == "2w" - assert json.loads(log.metadata_json)["namespace"] == "freshuser" - def test_create_user_policy_already_existing(initialized_db, app): with client_with_identity("devtable", app) as cl: @@ -277,19 +223,6 @@ def test_update_user_policy(initialized_db, app): assert get_response["method"] == "creation_date" assert get_response["value"] == "2w" - # Check audit log was created - logs = list(get_latest_logs_query(performer="devtable", namespace="devtable")) - log_kinds = get_log_entry_kinds() - log = None - for l in logs: - if l.kind == log_kinds["update_namespace_autoprune_policy"]: - log = l - break - assert log is not None - assert json.loads(log.metadata_json)["method"] == "creation_date" - assert json.loads(log.metadata_json)["value"] == "2w" - assert json.loads(log.metadata_json)["namespace"] == "devtable" - def test_update_user_policy_nonexistent_policy(initialized_db, app): with client_with_identity("devtable", app) as cl: @@ -323,18 +256,6 @@ def test_delete_user_policy(initialized_db, app): expected_code=404, ) - # Check audit log was created - logs = list(get_latest_logs_query(performer="devtable", namespace="devtable")) - log_kinds = get_log_entry_kinds() - log = None - for l in logs: - if l.kind == log_kinds["delete_namespace_autoprune_policy"]: - log = l - break - assert log is not None - assert json.loads(log.metadata_json)["policy_uuid"] == policy_uuid - assert json.loads(log.metadata_json)["namespace"] == "devtable" - def test_delete_user_policy_nonexistent_policy(initialized_db, app): with client_with_identity("devtable", app) as cl: diff --git a/endpoints/api/test/test_security.py b/endpoints/api/test/test_security.py index ecbb43eef7..3d5a822e29 100644 --- a/endpoints/api/test/test_security.py +++ b/endpoints/api/test/test_security.py @@ -6047,7 +6047,7 @@ OrganizationRhSku, "POST", {"orgname": "buynlarge"}, - {"subscriptions": [{"subscription_id": 12345}]}, + {"subscription_id": 12345}, None, 401, ), @@ -6059,14 +6059,6 @@ None, 401, ), - ( - OrganizationRhSkuBatchRemoval, - "POST", - {"orgname": "buynlarge"}, - {"subscriptions": [{"subscription_id": 12345}]}, - None, - 401, - ), (OrgAutoPrunePolicies, "GET", {"orgname": "buynlarge"}, None, None, 401), (OrgAutoPrunePolicies, "GET", {"orgname": "buynlarge"}, None, "devtable", 200), (OrgAutoPrunePolicies, "GET", {"orgname": "unknown"}, None, "devtable", 403), diff --git a/endpoints/api/test/test_superuser.py b/endpoints/api/test/test_superuser.py index b4d1d0d2ec..c7b5d04122 100644 --- a/endpoints/api/test/test_superuser.py +++ b/endpoints/api/test/test_superuser.py @@ -1,3 +1,5 @@ +from test.fixtures import * + import pytest from data.database import DeletedNamespace, User @@ -8,7 +10,6 @@ ) from endpoints.api.test.shared import conduct_api_call from endpoints.test.shared import client_with_identity -from test.fixtures import * @pytest.mark.parametrize( @@ -31,7 +32,7 @@ def test_list_all_users(disabled, app): def test_list_all_orgs(app): with client_with_identity("devtable", app) as cl: result = conduct_api_call(cl, SuperUserOrganizationList, "GET", None, None, 200).json - assert len(result["organizations"]) == 6 + assert len(result["organizations"]) == 5 def test_paginate_orgs(app): @@ -44,7 +45,7 @@ def test_paginate_orgs(app): secondResult = conduct_api_call( cl, SuperUserOrganizationList, "GET", params, None, 200 ).json - assert len(secondResult["organizations"]) == 3 + assert len(secondResult["organizations"]) == 2 assert secondResult.get("next_page", None) is None @@ -56,7 +57,7 @@ def test_paginate_test_list_all_users(app): assert firstResult["next_page"] is not None params["next_page"] = firstResult["next_page"] secondResult = conduct_api_call(cl, SuperUserList, "GET", params, None, 200).json - assert len(secondResult["users"]) == 5 + assert len(secondResult["users"]) == 4 assert secondResult.get("next_page", None) is None diff --git a/initdb.py b/initdb.py index 456c6f97be..f279d2217b 100644 --- a/initdb.py +++ b/initdb.py @@ -456,10 +456,6 @@ def initialize_database(): LogEntryKind.create(name="permanently_delete_tag") LogEntryKind.create(name="autoprune_tag_delete") - LogEntryKind.create(name="create_namespace_autoprune_policy") - LogEntryKind.create(name="update_namespace_autoprune_policy") - LogEntryKind.create(name="delete_namespace_autoprune_policy") - ImageStorageLocation.create(name="local_eu") ImageStorageLocation.create(name="local_us") @@ -646,12 +642,6 @@ def populate_database(minimal=False): outside_org.verified = True outside_org.save() - subscriptionuser = model.user.create_user( - "subscription", "password", "subscriptions@devtable.com" - ) - subscriptionuser.verified = True - subscriptionuser.save() - model.notification.create_notification( "test_notification", new_user_1, @@ -931,11 +921,6 @@ def populate_database(minimal=False): ) thirdorg.save() - subscriptionsorg = model.organization.create_organization( - "subscriptionsorg", "quay+subscriptionsorg@devtable.com", subscriptionuser - ) - subscriptionsorg.save() - model.user.create_robot("coolrobot", org) proxyorg = model.organization.create_organization( diff --git a/oauth/services/rhsso.py b/oauth/services/rhsso.py index 32dc653627..b011425527 100644 --- a/oauth/services/rhsso.py +++ b/oauth/services/rhsso.py @@ -60,17 +60,6 @@ def exchange_code_for_login(self, app_config, http_client, code, redirect_suffix # This generates a generic OAUTH error page # also any issues with reaching the export # compliance API should trigger this - # Adding error log to capture the error on sentry without causing quay.io logins to fail - msg = "" - if result: - msg = f"Got unknown response from export compliance service: {result.text}, with status_code: {result.status_code}" - - logger.error( - f"{msg}" - f"for sub: {sub}, lusername: {lusername}" - f"Failing with exception as: {str(e)}", - extra={"stack": True}, - exc_info=True, - ) + raise OAuthLoginException(str(e)) return sub, lusername, email_address diff --git a/static/css/directives/ui/org-binding.css b/static/css/directives/ui/org-binding.css deleted file mode 100644 index eab2ffe4c4..0000000000 --- a/static/css/directives/ui/org-binding.css +++ /dev/null @@ -1,11 +0,0 @@ -.org-binding-settings-element .btn { - margin-top: 10px; -} - -.org-binding-settings-element .form-control { - margin-top: 10px; -} - -.org-binding-settings-element td.add-remove-section { - margin: 10px; -} diff --git a/static/directives/billing-management-panel.html b/static/directives/billing-management-panel.html index a4d3b6cf62..3049d8d4da 100644 --- a/static/directives/billing-management-panel.html +++ b/static/directives/billing-management-panel.html @@ -5,16 +5,16 @@ Current Plan: -
+
{{ subscription.usedPrivateRepos }} private repositories exceeds the amount allowed by your plan. Upgrade your plan to avoid service disruptions.
-
+
{{ subscription.usedPrivateRepos }} private repositories is the maximum allowed by your plan. Upgrade your plan to create more private repositories.
{{ currentPlan.privateRepos }} private repositories -
Up to {{ currentPlan.privateRepos + currentMarketplace}} private repositories, unlimited public repositories
+
Up to {{ currentPlan.privateRepos }} private repositories, unlimited public repositories
@@ -77,4 +77,4 @@
-
+
\ No newline at end of file diff --git a/static/directives/header-bar.html b/static/directives/header-bar.html index 516b0c5461..23a889600f 100644 --- a/static/directives/header-bar.html +++ b/static/directives/header-bar.html @@ -44,7 +44,7 @@