├── .github ├── dependabot.yml ├── update-deployment.sh └── workflows │ ├── admin-publish.yaml │ ├── agnosticv-operator-publish.yaml │ ├── catalog-api-publish.yaml │ ├── catalog-manager-publish.yaml │ ├── catalog-status-publish.yaml │ ├── catalog-ui-pr.yaml │ ├── catalog-ui-publish.yaml │ ├── cost-tracker-publish.yaml │ ├── lab-ui-manager-publish.yaml │ ├── notifier-publish.yaml │ ├── publish-helm-charts.yaml │ ├── ratings-publish.yaml │ └── workshop-manager-publish.yaml ├── .gitignore ├── .gitlab-ci.yml ├── LICENSE ├── README.adoc ├── admin ├── .gitignore ├── .s2i │ └── bin │ │ ├── assemble │ │ └── run ├── Dockerfile ├── README.adoc ├── api │ ├── app.py │ ├── babylon.py │ ├── json_formatter.py │ ├── logconfig.yaml │ ├── models │ │ ├── __init__.py │ │ ├── babylon_admin │ │ │ ├── __init__.py │ │ │ └── incident.py │ │ ├── custom_base.py │ │ ├── database.py │ │ └── requirements.txt │ ├── routers │ │ ├── __init__.py │ │ ├── incidents.py │ │ ├── router_helper.py │ │ └── support.py │ └── schemas │ │ ├── __init__.py │ │ ├── incidents.py │ │ └── support.py ├── build-template.yaml ├── helm │ ├── Chart.yaml │ ├── templates │ │ ├── _helpers.tpl │ │ ├── database-secrets.yaml │ │ ├── deployment.yaml │ │ ├── namespace.yaml │ │ ├── rbac.yaml │ │ ├── service.yaml │ │ ├── serviceaccount.yaml │ │ └── servicenow-secret.yaml │ └── values.yaml └── requirements.txt ├── agnosticv-operator ├── .gitignore ├── .s2i │ └── bin │ │ └── assemble ├── .ssh │ └── known_hosts ├── Containerfile ├── Development.adoc ├── README.adoc ├── build-template.yaml ├── bump-version.sh ├── devfile.yaml ├── helm │ ├── Chart.yaml │ ├── crds │ │ ├── agnosticvcomponents.yaml │ │ └── agnosticvrepos.yaml │ ├── templates │ │ ├── _helpers.tpl │ │ ├── agnosticvrepos.yaml │ │ ├── clusterrole.yaml │ │ ├── clusterrolebinding.yaml │ │ ├── deployment.yaml │ │ ├── namespace.yaml │ │ ├── role.yaml │ │ ├── rolebinding.yaml │ │ └── serviceaccount.yaml │ └── values.yaml ├── kopf-opt.sh ├── operator │ ├── agnosticvcomponent.py │ ├── agnosticvrepo.py │ ├── babylon.py │ ├── cachedkopfobject.py │ ├── catalogitem.py │ ├── configure_kopf_logging.py │ ├── infinite_relative_backoff.py │ ├── k8sobject.py │ ├── kopfobject.py │ └── operator.py ├── requirements.txt ├── test.yml └── test │ ├── ansible.cfg │ ├── hosts │ ├── playbook.yaml │ └── roles │ └── test_core │ ├── defaults │ └── main.yml │ ├── files │ ├── account1.component-1.prod.anarchygovernor.yaml │ ├── account1.component-1.prod.catalogitem.yaml │ ├── account1.component-1.prod.resourceprovider.yaml │ ├── babylon-agnosticv-test.agnosticvrepo.yml │ └── babylon-agnosticv-test.secret.yml │ └── tasks │ ├── cleanup.yml │ ├── main.yml │ ├── setup.yml │ ├── teardown.yml │ └── test.yml ├── catalog-manager ├── .gitignore ├── Development.adoc ├── Dockerfile ├── build-template.yaml ├── devfile.yaml ├── helm │ ├── Chart.yaml │ ├── templates │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── gpte-db-secrets.yaml │ │ ├── namespace.yaml │ │ ├── rbac.yaml │ │ ├── salesforce-api-secret.yaml │ │ └── serviceaccount.yaml │ └── values.yaml ├── kopf-opt.sh ├── operator │ ├── babylon.py │ ├── catalog_item.py │ ├── catalog_item_service.py │ ├── configure_kopf_logging.py │ ├── infinite_relative_backoff.py │ ├── operator.py │ ├── rating.py │ └── utils.py └── requirements.txt ├── catalog ├── Development.adoc ├── README.adoc ├── api │ ├── Containerfile │ ├── README.adoc │ ├── app.py │ ├── config.py │ ├── hotfix.py │ ├── randomstring.py │ └── requirements.txt ├── babylon-catalog.route.yaml ├── build-template.yaml ├── helm │ ├── Chart.yaml │ ├── templates │ │ ├── _helpers.tpl │ │ ├── access │ │ │ └── clusterrole.yaml │ │ ├── api │ │ │ ├── clusterrole.yaml │ │ │ ├── clusterrolebinding.yaml │ │ │ ├── deployment.yaml │ │ │ ├── salesforce-api-secret.yaml │ │ │ ├── service.yaml │ │ │ └── serviceaccount.yaml │ │ ├── namespace.yaml │ │ ├── oauth-proxy │ │ │ ├── clientSecret.yaml │ │ │ ├── cookieSecret.yaml │ │ │ ├── deployment.yaml │ │ │ ├── oauthclient.yaml │ │ │ ├── route.yaml │ │ │ ├── service.yaml │ │ │ └── serviceaccount.yaml │ │ ├── redis │ │ │ ├── deployment.yaml │ │ │ ├── secret.yaml │ │ │ └── service.yaml │ │ ├── status │ │ │ ├── deployment.yaml │ │ │ └── service.yaml │ │ └── ui │ │ │ ├── deployment.yaml │ │ │ └── service.yaml │ └── values.yaml ├── jmeter │ ├── README.md │ ├── REDHAT_TEST_10-08-2021.jmx │ └── example.csv ├── status │ ├── Dockerfile │ ├── assets │ │ └── favicon.ico │ ├── index.html │ ├── interfaces │ │ ├── rhdp-partners.json │ │ └── rhpds.json │ ├── main.css │ ├── main.js │ └── nginx-default-cfg │ │ └── redirect.conf ├── ui │ ├── .dockerignore │ ├── .editorconfig │ ├── .eslintrc │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc │ ├── Dockerfile │ ├── LICENSE │ ├── README.adoc │ ├── __mocks__ │ │ ├── fileMock.js │ │ └── styleMock.js │ ├── babel.config.js │ ├── dr-surge.js │ ├── jest.config.js │ ├── nginx-default-cfg │ │ └── redirect.conf │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── app │ │ │ ├── Admin │ │ │ │ ├── AnarchyActionInstance.tsx │ │ │ │ ├── AnarchyActionSelect.tsx │ │ │ │ ├── AnarchyActions.tsx │ │ │ │ ├── AnarchyActionsTable.tsx │ │ │ │ ├── AnarchyGovernorInstance.tsx │ │ │ │ ├── AnarchyGovernors.tsx │ │ │ │ ├── AnarchyRunInstance.tsx │ │ │ │ ├── AnarchyRunnerStateSelect.tsx │ │ │ │ ├── AnarchyRuns.tsx │ │ │ │ ├── AnarchyRunsTable.tsx │ │ │ │ ├── AnarchySubjectInstance.tsx │ │ │ │ ├── AnarchySubjectStateSelect.tsx │ │ │ │ ├── AnarchySubjects.tsx │ │ │ │ ├── AnarchySubjectsTable.tsx │ │ │ │ ├── CatalogIncidentsAlertList.tsx │ │ │ │ ├── CatalogItemAdmin.spec.tsx │ │ │ │ ├── CatalogItemAdmin.tsx │ │ │ │ ├── CreateResourcePoolFromResourceHandleModal.tsx │ │ │ │ ├── IncidentsAlertList.tsx │ │ │ │ ├── IncidentsPage.tsx │ │ │ │ ├── RatingsList.tsx │ │ │ │ ├── RatingsPage.tsx │ │ │ │ ├── ResourceClaims.tsx │ │ │ │ ├── ResourceHandleInstance.tsx │ │ │ │ ├── ResourceHandles.tsx │ │ │ │ ├── ResourcePoolInstance.tsx │ │ │ │ ├── ResourcePoolMinAvailableInput.tsx │ │ │ │ ├── ResourcePoolStats.tsx │ │ │ │ ├── ResourcePools.tsx │ │ │ │ ├── ResourceProviderInstance.tsx │ │ │ │ ├── ResourceProviders.tsx │ │ │ │ ├── Workshops.tsx │ │ │ │ ├── WorkshopsScheduled.tsx │ │ │ │ ├── admin.css │ │ │ │ ├── catalog-item-admin.css │ │ │ │ └── usePoolStatus.tsx │ │ │ ├── AppLayout │ │ │ │ ├── AppLayout.spec.tsx │ │ │ │ ├── AppLayout.tsx │ │ │ │ ├── Navigation.tsx │ │ │ │ └── useStatusPageEmbed.ts │ │ │ ├── Catalog │ │ │ │ ├── Catalog.spec.tsx │ │ │ │ ├── Catalog.tsx │ │ │ │ ├── CatalogCategorySelector.tsx │ │ │ │ ├── CatalogContent.tsx │ │ │ │ ├── CatalogGridList.tsx │ │ │ │ ├── CatalogInterfaceDescription.tsx │ │ │ │ ├── CatalogItemCard.tsx │ │ │ │ ├── CatalogItemDetails.spec.tsx │ │ │ │ ├── CatalogItemDetails.tsx │ │ │ │ ├── CatalogItemForm.spec.tsx │ │ │ │ ├── CatalogItemForm.tsx │ │ │ │ ├── CatalogItemFormAutoStopDestroyModal.tsx │ │ │ │ ├── CatalogItemFormReducer.ts │ │ │ │ ├── CatalogItemHealthDisplay.tsx │ │ │ │ ├── CatalogItemIcon.tsx │ │ │ │ ├── CatalogItemListItem.tsx │ │ │ │ ├── CatalogLabelSelector.tsx │ │ │ │ ├── CatalogNamespaceSelect.tsx │ │ │ │ ├── CatalogRedirections.spec.tsx │ │ │ │ ├── CatalogRedirections.tsx │ │ │ │ ├── catalog-category-selector.css │ │ │ │ ├── catalog-item-card.css │ │ │ │ ├── catalog-item-details.css │ │ │ │ ├── catalog-item-form.css │ │ │ │ ├── catalog-item-list-item.css │ │ │ │ ├── catalog-item-request.css │ │ │ │ ├── catalog-item-workshop-form.css │ │ │ │ ├── catalog-label-selector.css │ │ │ │ ├── catalog-namespace-select.css │ │ │ │ ├── catalog-utils.ts │ │ │ │ ├── catalog.css │ │ │ │ └── icons │ │ │ │ │ └── openshift.png │ │ │ ├── Dashboard │ │ │ │ └── index.tsx │ │ │ ├── Header │ │ │ │ ├── Header.tsx │ │ │ │ ├── PublicHeader.tsx │ │ │ │ └── header.css │ │ │ ├── Modal │ │ │ │ ├── Modal.spec.tsx │ │ │ │ ├── Modal.tsx │ │ │ │ ├── modal.css │ │ │ │ └── useModal.tsx │ │ │ ├── NotFound │ │ │ │ └── NotFound.tsx │ │ │ ├── Services │ │ │ │ ├── InfoTab.tsx │ │ │ │ ├── ServiceActions.spec.tsx │ │ │ │ ├── ServiceActions.tsx │ │ │ │ ├── ServiceItemStatus.tsx │ │ │ │ ├── ServiceOpenStackConsole.tsx │ │ │ │ ├── ServiceStatus.spec.tsx │ │ │ │ ├── ServiceStatus.tsx │ │ │ │ ├── ServiceUsers.tsx │ │ │ │ ├── Services.tsx │ │ │ │ ├── ServicesAction.tsx │ │ │ │ ├── ServicesActionRating.tsx │ │ │ │ ├── ServicesCreateWorkshop.tsx │ │ │ │ ├── ServicesItem.tsx │ │ │ │ ├── ServicesList.tsx │ │ │ │ ├── ServicesScheduleAction.tsx │ │ │ │ ├── renderResourceClaimRow.tsx │ │ │ │ ├── renderWorkshopRow.tsx │ │ │ │ ├── service-item-status.css │ │ │ │ ├── service-status.css │ │ │ │ ├── service-utils.ts │ │ │ │ ├── services-delete-modal.css │ │ │ │ ├── services-item.css │ │ │ │ ├── services-list.css │ │ │ │ └── services-schedule-action-modal.css │ │ │ ├── Support │ │ │ │ ├── SupportPage.tsx │ │ │ │ └── support-page.css │ │ │ ├── Workshop │ │ │ │ ├── Workshop.tsx │ │ │ │ ├── WorkshopContent.tsx │ │ │ │ ├── WorkshopHeader.tsx │ │ │ │ ├── WorkshopLogin.tsx │ │ │ │ ├── workshop-content.css │ │ │ │ ├── workshop-login.css │ │ │ │ ├── workshop-utils.ts │ │ │ │ ├── workshop.css │ │ │ │ └── workshopApi.ts │ │ │ ├── Workshops │ │ │ │ ├── WorkshopActions.tsx │ │ │ │ ├── WorkshopScheduleAction.tsx │ │ │ │ ├── WorkshopStatus.tsx │ │ │ │ ├── WorkshopsItem.tsx │ │ │ │ ├── WorkshopsItemDetails.tsx │ │ │ │ ├── WorkshopsItemProvisioning.tsx │ │ │ │ ├── WorkshopsItemProvisioningItem.tsx │ │ │ │ ├── WorkshopsItemServices.tsx │ │ │ │ ├── WorkshopsItemUserAssignments.tsx │ │ │ │ ├── workshops-item-details.css │ │ │ │ ├── workshops-item-services.css │ │ │ │ ├── workshops-item.css │ │ │ │ └── workshops-utils.tsx │ │ │ ├── __mocks__ │ │ │ │ ├── anarchySubject--start-failed.json │ │ │ │ ├── anarchySubject.json │ │ │ │ ├── api.ts │ │ │ │ ├── catalogItem.json │ │ │ │ ├── catalogItemIncident.json │ │ │ │ ├── catalogItems.json │ │ │ │ └── resourceClaim.json │ │ │ ├── api.ts │ │ │ ├── app.css │ │ │ ├── app.spec.tsx │ │ │ ├── bgimages │ │ │ │ ├── Patternfly-Logo.svg │ │ │ │ ├── RHPDS-Logo-Beta.svg │ │ │ │ ├── RHPDS-Logo.svg │ │ │ │ ├── RedHat-Logo.svg │ │ │ │ ├── Summit-Logo.svg │ │ │ │ ├── external-link.svg │ │ │ │ ├── hero-img.jpeg │ │ │ │ ├── octicons-16.svg │ │ │ │ └── openshift-icon.svg │ │ │ ├── components │ │ │ │ ├── ActionDropdown.tsx │ │ │ │ ├── ActivityPurposeSelector.tsx │ │ │ │ ├── AdocWrapper.tsx │ │ │ │ ├── AnsibleRunLog.tsx │ │ │ │ ├── AutoStopDestroy.tsx │ │ │ │ ├── BulkUserAssignmentModal.tsx │ │ │ │ ├── ButtonCircleIcon.tsx │ │ │ │ ├── ConditionalWrapper.tsx │ │ │ │ ├── CopyToClipboard.tsx │ │ │ │ ├── CurrencyAmount.tsx │ │ │ │ ├── DateTimePicker.tsx │ │ │ │ ├── DynamicFormInput.tsx │ │ │ │ ├── EditableText.tsx │ │ │ │ ├── Editor │ │ │ │ │ ├── AutoLinkPlugin.tsx │ │ │ │ │ ├── Editor.tsx │ │ │ │ │ ├── EditorViewer.tsx │ │ │ │ │ ├── Theme.tsx │ │ │ │ │ ├── ToolbarPlugin.tsx │ │ │ │ │ ├── editor.css │ │ │ │ │ └── images │ │ │ │ │ │ ├── emoji │ │ │ │ │ │ ├── 1F600.png │ │ │ │ │ │ ├── 1F641.png │ │ │ │ │ │ ├── 1F642.png │ │ │ │ │ │ ├── 2764.png │ │ │ │ │ │ └── LICENSE.md │ │ │ │ │ │ └── icons │ │ │ │ │ │ ├── LICENSE.md │ │ │ │ │ │ ├── arrow-clockwise.svg │ │ │ │ │ │ ├── arrow-counterclockwise.svg │ │ │ │ │ │ ├── chat-square-quote.svg │ │ │ │ │ │ ├── chevron-down.svg │ │ │ │ │ │ ├── code.svg │ │ │ │ │ │ ├── journal-code.svg │ │ │ │ │ │ ├── journal-text.svg │ │ │ │ │ │ ├── justify.svg │ │ │ │ │ │ ├── link.svg │ │ │ │ │ │ ├── list-ol.svg │ │ │ │ │ │ ├── list-ul.svg │ │ │ │ │ │ ├── pencil-fill.svg │ │ │ │ │ │ ├── text-center.svg │ │ │ │ │ │ ├── text-left.svg │ │ │ │ │ │ ├── text-paragraph.svg │ │ │ │ │ │ ├── text-right.svg │ │ │ │ │ │ ├── type-bold.svg │ │ │ │ │ │ ├── type-h1.svg │ │ │ │ │ │ ├── type-h2.svg │ │ │ │ │ │ ├── type-h3.svg │ │ │ │ │ │ ├── type-italic.svg │ │ │ │ │ │ ├── type-strikethrough.svg │ │ │ │ │ │ └── type-underline.svg │ │ │ │ ├── ErrorBoundaryPage.tsx │ │ │ │ ├── Footer.tsx │ │ │ │ ├── Hero.tsx │ │ │ │ ├── ImpersonateUserModal.tsx │ │ │ │ ├── IncidentsBanner.tsx │ │ │ │ ├── KeywordSearchInput.tsx │ │ │ │ ├── LabInterfaceLink.tsx │ │ │ │ ├── Label.tsx │ │ │ │ ├── LoadingIcon.tsx │ │ │ │ ├── LoadingSection.tsx │ │ │ │ ├── LocalTimestamp.tsx │ │ │ │ ├── NotFound.tsx │ │ │ │ ├── OpenshiftConsoleLink.tsx │ │ │ │ ├── PatientNumberInput.tsx │ │ │ │ ├── ProjectSelector.tsx │ │ │ │ ├── RedHatLogo.tsx │ │ │ │ ├── RefreshButton.tsx │ │ │ │ ├── ResourceClaimDeleteModal.tsx │ │ │ │ ├── ResourceClaimStartModal.tsx │ │ │ │ ├── ResourceClaimStopModal.tsx │ │ │ │ ├── SearchInputString.tsx │ │ │ │ ├── SearchSalesforceIdModal.tsx │ │ │ │ ├── SelectableTable.tsx │ │ │ │ ├── SelectableTableWithPagination.tsx │ │ │ │ ├── ShareLink.tsx │ │ │ │ ├── StarRating.tsx │ │ │ │ ├── StatusPageIcons │ │ │ │ │ ├── DegradedPerformance.tsx │ │ │ │ │ ├── MajorOutage.tsx │ │ │ │ │ ├── Operational.tsx │ │ │ │ │ ├── PartialOutage.tsx │ │ │ │ │ ├── UnderMaintenance.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── TermsOfService.tsx │ │ │ │ ├── TimeInterval.tsx │ │ │ │ ├── UnexpectedError.tsx │ │ │ │ ├── UptimeDisplay.tsx │ │ │ │ ├── UserInterfaceLogo.tsx │ │ │ │ ├── WorkshopActionModal.tsx │ │ │ │ ├── action-dropdown.css │ │ │ │ ├── adoc-wrapper.css │ │ │ │ ├── ansible-run-log.css │ │ │ │ ├── bulk-user-assignment-modal.css │ │ │ │ ├── button-circle-icon.css │ │ │ │ ├── date-time-picker.css │ │ │ │ ├── editable-text.css │ │ │ │ ├── footer.css │ │ │ │ ├── impersonate-user-modal.css │ │ │ │ ├── incidents-banner.css │ │ │ │ ├── loading-icon.css │ │ │ │ ├── openshift-console-link.css │ │ │ │ └── project-selector.css │ │ │ ├── custom-media.css │ │ │ ├── index.tsx │ │ │ ├── reducers.ts │ │ │ ├── routes.tsx │ │ │ ├── store │ │ │ │ └── index.ts │ │ │ ├── types.ts │ │ │ ├── util.ts │ │ │ └── utils │ │ │ │ ├── react-window-scroller.tsx │ │ │ │ ├── test-utils.tsx │ │ │ │ ├── useDebounce.tsx │ │ │ │ ├── useDocumentTitle.ts │ │ │ │ ├── useHelpLink.tsx │ │ │ │ ├── useImpersonateUser.tsx │ │ │ │ ├── useInterfaceConfig.tsx │ │ │ │ ├── useMatchMutate.tsx │ │ │ │ ├── useRect.tsx │ │ │ │ ├── useScript.ts │ │ │ │ └── useSession.tsx │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── index.tsx │ │ ├── public │ │ │ ├── incidents_technical_support.csv │ │ │ ├── interfaces │ │ │ │ ├── rhdp-partners.json │ │ │ │ └── rhpds.json │ │ │ └── monitor.js │ │ └── typings.d.ts │ ├── stylePaths.js │ ├── test-setup.ts │ ├── tsconfig.json │ ├── webpack.common.js │ ├── webpack.dev.js │ └── webpack.prod.js └── util │ └── make-catalog-item.py ├── cost-tracker ├── .gitignore ├── Development.adoc ├── Dockerfile ├── build-template.yaml ├── devfile.yaml ├── helm │ ├── Chart.yaml │ ├── templates │ │ ├── _helpers.tpl │ │ ├── aws-sandbox-manager-secret.yaml │ │ ├── deployment.yaml │ │ ├── namespace.yaml │ │ ├── rbac.yaml │ │ └── serviceaccount.yaml │ └── values.yaml ├── kopf-opt.sh ├── operator │ ├── anarchy_subject.py │ ├── aws_sandbox_cost.py │ ├── cost_tracker_state.py │ ├── infinite_relative_backoff.py │ ├── operator.py │ └── resource_claim.py └── requirements.txt ├── docs ├── Architecture_Poolboy.adoc ├── Configuring_OpenShift.adoc ├── Deploying_Babylon.adoc ├── Deploying_OpenShift.adoc ├── Deploying_dark_tower.adoc ├── Metrics.adoc ├── README.adoc └── images │ ├── BabylonArchitecture-Poolboy.png │ └── babylon-high-level.png ├── helm ├── .helmignore ├── Chart.yaml ├── crds │ ├── agnosticvcomponents.yaml │ ├── agnosticvrepos.yaml │ ├── catalogitems.babylon.gpte.redhat.com.yaml │ ├── workshopprovisions.babylon.gpte.redhat.com.yaml │ ├── workshops.babylon.gpte.redhat.com.yaml │ └── workshopuserassignments.babylon.gpte.redhat.com.yaml ├── templates │ ├── _helpers.tpl │ ├── admin │ │ ├── database-secrets.yaml │ │ ├── deployment.yaml │ │ ├── namespace.yaml │ │ ├── service.yaml │ │ ├── serviceaccount.yaml │ │ └── servicenow-secret.yaml │ ├── agnosticv │ │ ├── agnosticvrepos.yaml │ │ └── operator │ │ │ ├── clusterrole.yaml │ │ │ ├── clusterrolebinding.yaml │ │ │ ├── deployment.yaml │ │ │ ├── role.yaml │ │ │ ├── rolebinding.yaml │ │ │ └── serviceaccount.yaml │ ├── anarchy │ │ ├── anarchy-runner-access.yaml │ │ ├── clusterroles.yaml │ │ ├── communes.yaml │ │ └── namespaces.yaml │ ├── catalog │ │ ├── interfaces │ │ │ ├── api │ │ │ │ ├── clusterrole.yaml │ │ │ │ ├── clusterrolebinding.yaml │ │ │ │ ├── deployment.yaml │ │ │ │ ├── salesforce-api-secret.yaml │ │ │ │ ├── service.yaml │ │ │ │ └── serviceaccount.yaml │ │ │ ├── namespaces.yaml │ │ │ ├── oauth-proxy │ │ │ │ ├── certificate.yaml │ │ │ │ ├── deployment.yaml │ │ │ │ ├── oauth-proxy-cookie-secret.yaml │ │ │ │ ├── oauthclientconfig.yaml │ │ │ │ ├── route.yaml │ │ │ │ ├── service.yaml │ │ │ │ ├── serviceaccount.yaml │ │ │ │ └── templates-configmap.yaml │ │ │ ├── redis │ │ │ │ ├── deployment.yaml │ │ │ │ ├── secret.yaml │ │ │ │ └── service.yaml │ │ │ ├── status │ │ │ │ ├── deployment.yaml │ │ │ │ └── service.yaml │ │ │ └── ui │ │ │ │ ├── deployment.yaml │ │ │ │ └── service.yaml │ │ └── namespaces.yaml │ ├── clusterroles │ │ ├── babylon-cluster-admin.yaml │ │ ├── babylon-cluster-reader.yaml │ │ ├── babylon-user-catalog-access.yaml │ │ ├── babylon-user-service-access.yaml │ │ ├── babylon-workshop-admin.yaml │ │ └── catalog-access.yaml │ ├── config │ │ └── namespace.yaml │ ├── notifier │ │ ├── anarchy-access.yaml │ │ ├── clusterrole.yaml │ │ ├── clusterrolebinding.yaml │ │ ├── deployment.yaml │ │ ├── namespace.yaml │ │ ├── redis │ │ │ ├── deployment.yaml │ │ │ ├── persistentvolumeclaim.yaml │ │ │ ├── secret.yaml │ │ │ └── service.yaml │ │ ├── serviceaccount.yaml │ │ └── smtp-secret.yaml │ ├── resourceBroker │ │ ├── clusterrole.yaml │ │ └── clusterrolebinding.yaml │ └── workshopManager │ │ ├── clusterrole.yaml │ │ ├── clusterrolebinding.yaml │ │ ├── deployment.yaml │ │ ├── namespace.yaml │ │ └── serviceaccount.yaml └── values.yaml ├── lab-ui-manager ├── .gitignore ├── Development.adoc ├── Dockerfile ├── README.adoc ├── build-template.yaml ├── devfile.yaml ├── helm │ ├── Chart.yaml │ ├── crds │ │ ├── bookbagbuilds.babylon.gpte.redhat.com.yaml │ │ └── bookbagdeployments.babylon.gpte.redhat.com.yaml │ ├── templates │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── namespace.yaml │ │ ├── rbac.yaml │ │ └── serviceaccount.yaml │ └── values.yaml ├── kopf-opt.sh ├── operator │ ├── infinite_relative_backoff.py │ └── operator.py ├── requirements.txt ├── user-configmap.resourceclaim.yaml ├── user-configmap.resourcehandle.yaml └── user-configmap.resourceprovider.yaml ├── notifier ├── .gitignore ├── .s2i │ └── bin │ │ └── assemble ├── Containerfile ├── Development.adoc ├── README.adoc ├── build-template.yaml ├── devfile.yaml ├── helm │ ├── Chart.yaml │ ├── templates │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── namespace.yaml │ │ ├── rbac.yaml │ │ ├── redis │ │ │ ├── deployment.yaml │ │ │ ├── pvc.yaml │ │ │ ├── secret.yaml │ │ │ └── service.yaml │ │ ├── serviceaccount.yaml │ │ ├── smtp-secret.yaml │ │ └── tls-secret.yaml │ └── values.yaml ├── kopf-opt.sh ├── operator │ ├── babylon.py │ ├── catalog_item.py │ ├── catalog_namespace.py │ ├── configure_kopf_logging.py │ ├── infinite_relative_backoff.py │ ├── operator.py │ ├── resource_claim.py │ ├── service_namespace.py │ └── templates │ │ ├── base.mjml.j2 │ │ ├── provision-failed.mjml.j2 │ │ ├── provision-started.mjml.j2 │ │ ├── retirement-scheduled.mjml.j2 │ │ ├── service-deleted.mjml.j2 │ │ ├── service-ready.mjml.j2 │ │ ├── start-complete.mjml.j2 │ │ ├── start-failed.mjml.j2 │ │ ├── stop-complete.mjml.j2 │ │ ├── stop-failed.mjml.j2 │ │ ├── stop-scheduled.mjml.j2 │ │ └── wrapper.mjml.j2 └── requirements.txt ├── openshift └── config │ ├── README.adoc │ ├── common │ ├── helm │ │ ├── babylon-admin │ │ ├── babylon-agnosticv-operator │ │ ├── babylon-catalog │ │ ├── babylon-catalog-manager │ │ ├── babylon-config │ │ │ ├── Chart.yaml │ │ │ ├── crds │ │ │ │ ├── catalogitems.babylon.gpte.redhat.com.yaml │ │ │ │ ├── workshopprovisions.babylon.gpte.redhat.com.yaml │ │ │ │ └── workshops.babylon.gpte.redhat.com.yaml │ │ │ ├── templates │ │ │ │ ├── anarchy.yaml │ │ │ │ ├── babylon-resourceprovider.yaml │ │ │ │ ├── catalog-namespaces.yaml │ │ │ │ ├── cross-cluster-backup.yaml │ │ │ │ ├── rbac.yaml │ │ │ │ ├── service-request-configmap.resourceprovider.yaml │ │ │ │ └── user-configmap.resourceprovider.yaml │ │ │ └── values.yaml │ │ ├── babylon-cost-tracker │ │ ├── babylon-lab-ui-manager │ │ ├── babylon-notifier │ │ ├── babylon-ratings │ │ └── babylon-workshop-manager │ ├── templates │ │ ├── anarchy-install.yaml.j2 │ │ └── anarchy-k8s-config │ │ │ └── anarchysubjects │ │ │ └── babylon.yaml.j2 │ └── vars.yaml │ ├── env │ ├── dev │ │ └── main.yaml │ ├── prod │ │ └── main.yaml │ └── test │ │ └── main.yaml │ ├── main.yaml │ └── setup-playbook.yaml ├── playbooks ├── filter_plugins │ └── parameters.py ├── service-destroy.yaml ├── service-lifecycle.yaml ├── service-provision.yaml ├── service-status.yaml ├── tasks │ └── write-tower-rc.yaml └── unittest-filter-plugins.py ├── ratings ├── .gitignore ├── .s2i │ └── bin │ │ ├── assemble │ │ └── run ├── Dockerfile ├── README.adoc ├── api │ ├── app.py │ ├── babylon.py │ ├── json_formatter.py │ ├── logconfig.yaml │ ├── models │ │ ├── __init__.py │ │ ├── bookmark.py │ │ ├── catalog_item.py │ │ ├── catalog_resource.py │ │ ├── custom_base.py │ │ ├── database.py │ │ ├── provision.py │ │ ├── provision_request.py │ │ ├── purpose.py │ │ ├── rating.py │ │ ├── reporting_config.py │ │ ├── requirements.txt │ │ ├── user.py │ │ ├── workshop.py │ │ └── workshop_assignment.py │ ├── routers │ │ ├── __init__.py │ │ ├── bookmarks.py │ │ ├── pagination.py │ │ └── ratings.py │ └── schemas │ │ ├── __init__.py │ │ ├── bookmarks.py │ │ ├── catalog_item.py │ │ ├── provision.py │ │ ├── purpose.py │ │ ├── ratings.py │ │ ├── request.py │ │ ├── user.py │ │ └── workshop.py ├── build-template.yaml ├── helm │ ├── Chart.yaml │ ├── templates │ │ ├── _helpers.tpl │ │ ├── database-secrets.yaml │ │ ├── deployment.yaml │ │ ├── namespace.yaml │ │ ├── rbac.yaml │ │ ├── service.yaml │ │ └── serviceaccount.yaml │ └── values.yaml └── requirements.txt ├── sonar-project.properties ├── test └── README.md ├── tools └── babylon-status │ ├── governor_versions.py │ ├── pool_status.py │ └── status.py └── workshop-manager ├── .gitignore ├── Containerfile ├── Development.adoc ├── README.adoc ├── build-template.yaml ├── devfile.yaml ├── helm ├── Chart.yaml ├── templates │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── namespace.yaml │ ├── rbac.yaml │ └── serviceaccount.yaml └── values.yaml ├── kopf-opt.sh ├── operator ├── babylon.py ├── cachedkopfobject.py ├── catalogitem.py ├── configure_kopf_logging.py ├── infinite_relative_backoff.py ├── k8sobject.py ├── kopfobject.py ├── labuserinterface.py ├── operator.py ├── resourceclaim.py ├── resourceprovider.py ├── userassignment.py ├── workshop.py ├── workshopprovision.py └── workshopuserassignment.py └── requirements.txt /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | # Enable version updates for npm 9 | - package-ecosystem: "npm" 10 | # Look for `package.json` and `lock` files in the `root` directory 11 | directory: "/catalog/ui" 12 | # Check the npm registry for updates every day (weekdays) 13 | schedule: 14 | interval: "daily" 15 | open-pull-requests-limit: 4 16 | labels: 17 | - "npm dependencies" 18 | 19 | # Enable version updates for Docker 20 | - package-ecosystem: "docker" 21 | # Look for a `Dockerfile` in the `root` directory 22 | directory: "/catalog/ui" 23 | # Check for updates once a week 24 | schedule: 25 | interval: "weekly" 26 | labels: 27 | - "Docker dependencies" 28 | -------------------------------------------------------------------------------- /.github/update-deployment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | app_name=$1 4 | image=$2 5 | namespace=$3 6 | container_name=$4 7 | 8 | deploy=`oc get deployment $app_name -n $namespace` 9 | if [[ "$?" -eq 0 ]]; then 10 | oc set image deployment/$app_name $container_name=$image -n $namespace 11 | oc rollout restart deployment/$app_name -n $namespace 12 | fi 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | notifier/values.yaml 2 | *.crt 3 | *.key 4 | *.swp 5 | __pycache__ 6 | .vscode 7 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | == Project Babylon 2 | 3 | Home to the documentation and shared resources for The Babylon Project 4 | 5 | image::docs/images/babylon-high-level.png[width=95%,align="center"] 6 | 7 | === Main Components 8 | 9 | * link:https://github.com/redhat-cop/agnosticd[AgnosticD - An Ansible based Cloud Agnostic Deployment Framework] 10 | * link:https://github.com/redhat-cop/agnosticv[AgnosticV - Catalog management, Configuration and vars for AgnosticD] 11 | * link:./agnosticv-operator[AgnosticV Operator] 12 | * link:https://github.com/redhat-cop/anarchy.git[Anarchy - OpenShift Operator for Stateless API operations] 13 | * link:https://github.com/redhat-cop/poolboy.git[Poolboy - OpenShift Operator to manage OpenShift resources] 14 | * link:https://github.com/rhpds/babylon_anarchy_governor[Anarchy Governor] 15 | * link:https://github.com/rhpds/sandbox[Sandbox] - Ephemeral accounts 16 | 17 | === Getting Started 18 | 19 | * Start with link:docs/Deploying_Babylon.adoc[Deploying Babylon Suite of Components] 20 | -------------------------------------------------------------------------------- /admin/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .odo -------------------------------------------------------------------------------- /admin/.s2i/bin/assemble: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | set -eo pipefail 5 | shopt -s dotglob 6 | 7 | mkdir -p /opt/app-root/src || : 8 | cp --preserve=mode --recursive /tmp/src/api /opt/app-root/ 9 | 10 | exec /usr/libexec/s2i/assemble -------------------------------------------------------------------------------- /admin/.s2i/bin/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | if [ "${COMPONENT}" == 'api' ] 5 | then 6 | export HOME=/opt/app-root/api 7 | cd $HOME 8 | exec uvicorn app:app --host 0.0.0.0 --port 8080 --lifespan on --log-level info --log-config logconfig.yaml 9 | else 10 | exec /usr/libexec/s2i/run 11 | fi -------------------------------------------------------------------------------- /admin/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.access.redhat.com/ubi9/python-311:latest 2 | 3 | USER root 4 | 5 | COPY . /tmp/src 6 | 7 | COPY ./.s2i/bin /tmp/scripts/s2i 8 | 9 | RUN rm -rf /tmp/src/.git* && \ 10 | chown -R 1001 /tmp/src && \ 11 | chown -R 1001 /tmp/scripts && \ 12 | chgrp -R 0 /tmp/src && \ 13 | chgrp -R 0 /tmp/scripts && \ 14 | chmod -R g+w /tmp/src && \ 15 | chmod -R +x /tmp/scripts 16 | 17 | USER 1001 18 | 19 | RUN /tmp/scripts/s2i/assemble 20 | 21 | CMD ["/tmp/scripts/s2i/run"] 22 | -------------------------------------------------------------------------------- /admin/api/babylon.py: -------------------------------------------------------------------------------- 1 | import kubernetes_asyncio 2 | import os 3 | 4 | class Babylon(): 5 | babylon_domain = os.environ.get('BABYLON_DOMAIN', 'babylon.gpte.redhat.com') 6 | babylon_api_version = os.environ.get('BABYLON_API_VERSION', 'v1') 7 | 8 | @classmethod 9 | async def on_cleanup(cls): 10 | await cls.core_v1_api.api_client.close() 11 | await cls.custom_objects_api.api_client.close() 12 | 13 | @classmethod 14 | async def on_startup(cls): 15 | if os.path.exists('/run/secrets/kubernetes.io/serviceaccount'): 16 | kubernetes_asyncio.config.load_incluster_config() 17 | else: 18 | await kubernetes_asyncio.config.load_kube_config() 19 | 20 | cls.core_v1_api = kubernetes_asyncio.client.CoreV1Api() 21 | cls.custom_objects_api = kubernetes_asyncio.client.CustomObjectsApi() 22 | -------------------------------------------------------------------------------- /admin/api/json_formatter.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import json 3 | 4 | 5 | class JSONFormatter(logging.Formatter): 6 | def format(self, record): 7 | log_data = { 8 | "time": self.formatTime(record, self.datefmt), 9 | "name": record.name, 10 | "level": record.levelname, 11 | "message": record.getMessage() 12 | } 13 | return json.dumps(log_data) 14 | -------------------------------------------------------------------------------- /admin/api/logconfig.yaml: -------------------------------------------------------------------------------- 1 | version: 1 2 | disable_existing_loggers: False 3 | formatters: 4 | timestamped: 5 | format: '%(asctime)s - %(levelname)s - %(message)s' 6 | json: 7 | (): json_formatter.JSONFormatter 8 | handlers: 9 | console: 10 | class: logging.StreamHandler 11 | level: INFO 12 | formatter: json 13 | stream: ext://sys.stdout 14 | root: 15 | level: INFO 16 | handlers: [console] 17 | -------------------------------------------------------------------------------- /admin/api/models/__init__.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import os 3 | 4 | from .custom_base import Base, CustomBase, CustomBaseUuid, CustomBaseProvisionUuid, create_tables 5 | from .database import Database 6 | from .babylon_admin import Incident 7 | 8 | 9 | async def startup(): 10 | """ 11 | This method initilize the database connection, few environment 12 | variables are required to work properly 13 | DB_USERNAME 14 | DB_PASSWORD 15 | DB_NAME 16 | DB_HOSTNAME 17 | DB_PORT 18 | SERVICENOW_AUTH_KEY 19 | SERVICENOW_FORM_ID 20 | """ 21 | 22 | # Define a list with the environment variables you need to check 23 | required_env_vars = ["DB_USERNAME", "DB_PASSWORD", "DB_NAME", "DB_HOSTNAME", "SERVICENOW_AUTH_KEY", "SERVICENOW_FORM_ID"] 24 | 25 | # Check if all environment variables exist 26 | for var in required_env_vars: 27 | value = os.getenv(var) 28 | if value is None: 29 | # If the variable doesn't exist, print an error message 30 | print(f"Error: environment variable {var} is not defined.") 31 | return 32 | 33 | await Database.initialize() 34 | -------------------------------------------------------------------------------- /admin/api/models/babylon_admin/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import (event, DDL) 2 | 3 | from .incident import Incident 4 | 5 | create_schema_ddl = DDL(""" 6 | CREATE SCHEMA IF NOT EXISTS babylon_admin; 7 | """) 8 | 9 | event.listen(Incident.__table__, "before_create", 10 | create_schema_ddl.execute_if(dialect="postgresql")) 11 | -------------------------------------------------------------------------------- /admin/api/models/requirements.txt: -------------------------------------------------------------------------------- 1 | asyncpg==0.27.0 2 | asyncpgsa==0.27.1 3 | psycopg2-binary==2.9.6 4 | sqlalchemy==2.0.15 5 | sqlalchemy-utils==0.41 6 | -------------------------------------------------------------------------------- /admin/api/routers/__init__.py: -------------------------------------------------------------------------------- 1 | from .support import router as support_router 2 | from .incidents import router as incidents_router -------------------------------------------------------------------------------- /admin/api/routers/router_helper.py: -------------------------------------------------------------------------------- 1 | from fastapi import Query 2 | 3 | 4 | def get_pagination_params( 5 | page: int = Query(1, description="Page number to retrieve"), 6 | per_page: int = Query(50, le=100, description="Number of items per page, max 100") 7 | ) -> dict: 8 | return {"page": page, "per_page": per_page} 9 | 10 | 11 | def get_status_params( 12 | status: str = Query(..., 13 | example="active", 14 | alias="status", 15 | title="Incident Status", 16 | description="The status of the incident (active, resolved, all).", 17 | regex='^(active|resolved|all)$'), 18 | interface: str = Query(..., 19 | example="rhpds", 20 | alias="interface", 21 | title="Interface origin", 22 | description="The interface where the incident is going to be displayed") 23 | ) -> dict: 24 | return {"status": status, "interface": interface} 25 | -------------------------------------------------------------------------------- /admin/api/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | from .incidents import IncidentSchema, StatusParams, IncidentStatus, IncidentCreate 2 | from .support import SupportCreate, SupportResponse -------------------------------------------------------------------------------- /admin/api/schemas/support.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional, Literal 2 | import logging 3 | from pydantic import BaseModel 4 | from datetime import datetime 5 | 6 | 7 | logger = logging.getLogger('babylon-api') 8 | 9 | 10 | class SupportCreate(BaseModel): 11 | number_of_attendees: int 12 | sfdc: Optional[str] 13 | name: str 14 | event_name: Optional[str] 15 | url: str 16 | start_time: Optional[datetime] 17 | end_time: Optional[datetime] 18 | email: str 19 | 20 | class SupportResponse(BaseModel): 21 | sys_id: str 22 | request_number: str 23 | request_id: str -------------------------------------------------------------------------------- /admin/helm/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: babylon-admin 3 | description: A Helm chart for the babylon admin component. 4 | type: application 5 | version: 1.0.7 6 | appVersion: 1.0.7 7 | -------------------------------------------------------------------------------- /admin/helm/templates/database-secrets.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.db.deploy -}} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ .Values.db.secretName }} 6 | namespace: {{ include "babylon-admin.namespaceName" . }} 7 | labels: 8 | {{- include "babylon-admin.labels" . | nindent 4 }} 9 | data: 10 | hostname: {{ required ".Values.db.hostname is required!" .Values.db.hostname | b64enc }} 11 | username: {{ required ".Values.db.username is required!" .Values.db.username | b64enc }} 12 | password: {{ required ".Values.db.password is required!" .Values.db.password | b64enc }} 13 | name: {{ required ".Values.db.name is required!" .Values.db.name | b64enc }} 14 | {{- end -}} 15 | -------------------------------------------------------------------------------- /admin/helm/templates/namespace.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Values.namespace.create }} 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: {{ include "babylon-admin.namespaceName" . }} 6 | {{ end }} 7 | -------------------------------------------------------------------------------- /admin/helm/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "babylon-admin.name" . }} 5 | namespace: {{ include "babylon-admin.namespaceName" . }} 6 | labels: 7 | {{- include "babylon-admin.labels" . | nindent 4 }} 8 | spec: 9 | type: ClusterIP 10 | ports: 11 | - name: admin-api 12 | port: 8080 13 | protocol: TCP 14 | targetPort: 8080 15 | selector: 16 | {{- include "babylon-admin.selectorLabels" . | nindent 4 }} -------------------------------------------------------------------------------- /admin/helm/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Values.deploy }} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "babylon-admin.serviceAccountName" . }} 6 | namespace: {{ include "babylon-admin.namespaceName" . }} 7 | labels: 8 | {{- include "babylon-admin.labels" . | nindent 4 }} 9 | {{ end }} 10 | -------------------------------------------------------------------------------- /admin/helm/templates/servicenow-secret.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.servicenow.deploy }} 2 | apiVersion: bitwarden-k8s-secrets-manager.demo.redhat.com/v1 3 | kind: BitwardenSyncSecret 4 | metadata: 5 | name: {{ .Values.servicenow.secretName | default "babylon-admin-servicenow" }} 6 | namespace: {{ include "babylon-admin.namespaceName" . }} 7 | spec: 8 | data: 9 | authKey: 10 | secret: service_now 11 | key: auth_key 12 | workshopFormId: 13 | secret: service_now 14 | key: workshop_form_id 15 | {{- else }} 16 | --- 17 | apiVersion: v1 18 | kind: Secret 19 | metadata: 20 | name: {{ .Values.servicenow.secretName | default "babylon-admin-servicenow" }} 21 | namespace: {{ include "babylon-admin.namespaceName" . }} 22 | labels: 23 | {{- include "babylon-admin.labels" . | nindent 4 }} 24 | data: 25 | authKey: {{ required ".Values.servicenow.authKey is required!" .Values.servicenow.authKey | b64enc }} 26 | workshopFormId: {{ required ".Values.servicenow.workshopFormId is required!" .Values.servicenow.workshopFormId | b64enc }} 27 | {{- end }} 28 | -------------------------------------------------------------------------------- /admin/requirements.txt: -------------------------------------------------------------------------------- 1 | SQLAlchemy-Utils==0.41.1 2 | SQLAlchemy==2.0.21 3 | asyncpg==0.28.0 4 | fastapi==0.109.1 5 | greenlet==3.0.0 6 | kubernetes-asyncio==28.2.0 7 | psycopg2==2.9.9 8 | pydantic==2.4.2 9 | uvicorn==0.23.2 10 | aiohttp==3.10.11 11 | asyncio==3.4.3 -------------------------------------------------------------------------------- /agnosticv-operator/.gitignore: -------------------------------------------------------------------------------- 1 | .odo/env 2 | .odo/odo-file-index.json 3 | agnosticvrepo*.yaml 4 | id_rsa 5 | id_rsa.pub 6 | test-helm-values.yaml 7 | -------------------------------------------------------------------------------- /agnosticv-operator/.s2i/bin/assemble: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | AGNOSTICV_VERSION=v0.8.1 3 | 4 | set -x 5 | set -eo pipefail 6 | shopt -s dotglob 7 | 8 | mkdir -p /opt/app-root/src || : 9 | mkdir -p /opt/app-root/bin || : 10 | mkdir -p /opt/app-root/.ssh || : 11 | cp .ssh/known_hosts /opt/app-root/.ssh/known_hosts 12 | 13 | if [[ ! -x /opt/app-root/bin/agnosticv ]] || [[ "${AGNOSTICV_VERSION}" != "$(/opt/app-root/bin/agnosticv --version | sed -ne 's/^Version: //p')" ]]; 14 | then 15 | curl -sL --retry 5 https://github.com/redhat-cop/agnosticv/releases/download/${AGNOSTICV_VERSION}/agnosticv_linux_amd64 -o /opt/app-root/bin/agnosticv 16 | chmod a+x /opt/app-root/bin/agnosticv 17 | fi 18 | 19 | exec /usr/libexec/s2i/assemble 20 | -------------------------------------------------------------------------------- /agnosticv-operator/.ssh/known_hosts: -------------------------------------------------------------------------------- 1 | github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl 2 | github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= 3 | github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== 4 | -------------------------------------------------------------------------------- /agnosticv-operator/Containerfile: -------------------------------------------------------------------------------- 1 | FROM quay.io/redhat-cop/python-kopf-s2i:v1.37 2 | 3 | USER 0 4 | 5 | COPY . /tmp/src 6 | 7 | RUN rm -rf /tmp/src/.git* && \ 8 | chown -R 1001 /tmp/src && \ 9 | chgrp -R 0 /tmp/src && \ 10 | chmod -R g+w /tmp/src && \ 11 | cp -rp /tmp/src/.s2i/bin /tmp/scripts 12 | 13 | USER 1001 14 | 15 | RUN cd /tmp/src && /tmp/scripts/assemble 16 | 17 | CMD ["/usr/libexec/s2i/run"] 18 | -------------------------------------------------------------------------------- /agnosticv-operator/README.adoc: -------------------------------------------------------------------------------- 1 | = Babylon Config Operator 2 | -------------------------------------------------------------------------------- /agnosticv-operator/helm/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: babylon-agnosticv-operator 4 | description: Operator for managing babylon configuraion from AgnosticV repositories 5 | type: application 6 | version: 1.10.2 7 | appVersion: 1.10.2 8 | -------------------------------------------------------------------------------- /agnosticv-operator/helm/templates/clusterrole.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: {{ include "babylonAgnosticVOperator.name" . }} 6 | labels: 7 | {{- include "babylonAgnosticVOperator.labels" . | nindent 4 }} 8 | rules: 9 | - apiGroups: 10 | - {{ .Values.anarchy.apiGroup }} 11 | resources: 12 | - anarchygovernors 13 | verbs: 14 | - create 15 | - delete 16 | - get 17 | - list 18 | - patch 19 | - update 20 | - watch 21 | - apiGroups: 22 | - {{ .Values.catalog.apiGroup }} 23 | resources: 24 | - catalogitems 25 | verbs: 26 | - create 27 | - delete 28 | - get 29 | - list 30 | - patch 31 | - update 32 | - watch 33 | - apiGroups: 34 | - {{ .Values.resourceBroker.apiGroup }} 35 | resources: 36 | - resourceproviders 37 | verbs: 38 | - create 39 | - delete 40 | - get 41 | - list 42 | - patch 43 | - update 44 | - watch 45 | -------------------------------------------------------------------------------- /agnosticv-operator/helm/templates/clusterrolebinding.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy -}} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | name: {{ include "babylonAgnosticVOperator.name" . }} 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: {{ include "babylonAgnosticVOperator.name" . }} 10 | subjects: 11 | - kind: ServiceAccount 12 | name: {{ include "babylonAgnosticVOperator.serviceAccountName" . }} 13 | namespace: {{ include "babylonAgnosticVOperator.namespaceName" $ }} 14 | {{- end -}} 15 | -------------------------------------------------------------------------------- /agnosticv-operator/helm/templates/namespace.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.namespace.create -}} 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: {{ include "babylonAgnosticVOperator.namespaceName" . }} 6 | labels: 7 | {{- include "babylonAgnosticVOperator.labels" . | nindent 4 }} 8 | {{- end -}} 9 | -------------------------------------------------------------------------------- /agnosticv-operator/helm/templates/rolebinding.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy -}} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: RoleBinding 4 | metadata: 5 | name: {{ include "babylonAgnosticVOperator.shortName" . }} 6 | namespace: {{ include "babylonAgnosticVOperator.namespaceName" . }} 7 | labels: 8 | {{- include "babylonAgnosticVOperator.labels" . | nindent 4 }} 9 | roleRef: 10 | apiGroup: rbac.authorization.k8s.io 11 | kind: Role 12 | name: {{ include "babylonAgnosticVOperator.shortName" . }} 13 | subjects: 14 | - kind: ServiceAccount 15 | name: {{ include "babylonAgnosticVOperator.serviceAccountName" . }} 16 | namespace: {{ include "babylonAgnosticVOperator.namespaceName" . }} 17 | {{- end -}} 18 | -------------------------------------------------------------------------------- /agnosticv-operator/helm/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.deploy .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "babylonAgnosticVOperator.serviceAccountName" . }} 6 | namespace: {{ include "babylonAgnosticVOperator.namespaceName" . }} 7 | labels: 8 | {{- include "babylonAgnosticVOperator.labels" . | nindent 4 }} 9 | {{- with .Values.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end -}} 14 | -------------------------------------------------------------------------------- /agnosticv-operator/kopf-opt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Use JSON log format 4 | KOPF_OPTIONS="--log-format=json" 5 | 6 | # Restrict watch to operator namespace. 7 | KOPF_NAMESPACED=true 8 | 9 | # Do not attempt to coordinate with other kopf operators. 10 | KOPF_STANDALONE=true 11 | -------------------------------------------------------------------------------- /agnosticv-operator/operator/configure_kopf_logging.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | def suppress_handler_succeeded_messages(record: logging.LogRecord) -> bool: 4 | txt = record.getMessage() 5 | if txt.startswith("Handler ") and txt.endswith(" succeeded."): 6 | return False 7 | if txt.endswith("is processed: 1 succeeded; 0 failed."): 8 | return False 9 | return True 10 | 11 | def configure_kopf_logging(): 12 | objlogger = logging.getLogger('kopf.objects') 13 | objlogger.addFilter(suppress_handler_succeeded_messages) 14 | -------------------------------------------------------------------------------- /agnosticv-operator/operator/infinite_relative_backoff.py: -------------------------------------------------------------------------------- 1 | class InfiniteRelativeBackoff: 2 | def __init__(self, initial_delay=0.1, scaling_factor=2, maximum=60): 3 | self.initial_delay = initial_delay 4 | self.scaling_factor = scaling_factor 5 | self.maximum = maximum 6 | 7 | def __iter__(self): 8 | delay = self.initial_delay 9 | while True: 10 | if delay > self.maximum: 11 | yield self.maximum 12 | else: 13 | yield delay 14 | delay *= self.scaling_factor 15 | -------------------------------------------------------------------------------- /agnosticv-operator/requirements.txt: -------------------------------------------------------------------------------- 1 | aiofiles==24.1.0 2 | aiohttp==3.11.11 3 | aioshutil==1.5 4 | GitPython==3.1.44 5 | Jinja2==3.1.6 6 | pytimeparse==1.1.8 7 | str2bool==1.1 8 | -------------------------------------------------------------------------------- /agnosticv-operator/test/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory = hosts 3 | -------------------------------------------------------------------------------- /agnosticv-operator/test/hosts: -------------------------------------------------------------------------------- 1 | [local] 2 | localhost ansible_connection=local ansible_python_interpreter={{ansible_playbook_python}} 3 | -------------------------------------------------------------------------------- /agnosticv-operator/test/playbook.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: false 4 | vars: 5 | test_namespace: babylon-config 6 | tests: 7 | - core 8 | tasks: 9 | - name: Cleanup to reset before Running tests 10 | include_role: 11 | name: "{{ __test_role }}" 12 | tasks_from: cleanup.yml 13 | loop: "{{ tests }}" 14 | loop_control: 15 | loop_var: __test 16 | vars: 17 | __test_role: test_{{ __test }} 18 | 19 | - name: Run tests 20 | include_role: 21 | name: "{{ __test_role }}" 22 | loop: "{{ tests }}" 23 | loop_control: 24 | loop_var: __test 25 | vars: 26 | __test_role: test_{{ __test }} 27 | -------------------------------------------------------------------------------- /agnosticv-operator/test/roles/test_core/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | babylon_agnosticv_operator_namespace: babylon-config 3 | -------------------------------------------------------------------------------- /agnosticv-operator/test/roles/test_core/tasks/cleanup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | -------------------------------------------------------------------------------- /agnosticv-operator/test/roles/test_core/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Setup for tests 3 | include_tasks: 4 | file: setup.yml 5 | - name: Run tests 6 | include_tasks: 7 | file: test.yml 8 | - name: Cleanup after running tests 9 | include_tasks: 10 | file: cleanup.yml 11 | - name: Teardown setup 12 | include_tasks: 13 | file: teardown.yml 14 | -------------------------------------------------------------------------------- /agnosticv-operator/test/roles/test_core/tasks/teardown.yml: -------------------------------------------------------------------------------- 1 | --- 2 | -------------------------------------------------------------------------------- /catalog-manager/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .odo -------------------------------------------------------------------------------- /catalog-manager/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM quay.io/redhat-cop/python-kopf-s2i:v1.37 2 | 3 | USER root 4 | 5 | COPY . /tmp/src 6 | 7 | RUN rm -rf /tmp/src/.git* && \ 8 | chown -R 1001 /tmp/src && \ 9 | chgrp -R 0 /tmp/src && \ 10 | chmod -R g+w /tmp/src 11 | 12 | USER 1001 13 | 14 | RUN /usr/libexec/s2i/assemble 15 | 16 | CMD ["/usr/libexec/s2i/run"] 17 | -------------------------------------------------------------------------------- /catalog-manager/devfile.yaml: -------------------------------------------------------------------------------- 1 | commands: 2 | - exec: 3 | commandLine: /usr/libexec/s2i/assemble 4 | component: s2i-builder 5 | group: 6 | isDefault: true 7 | kind: build 8 | hotReloadCapable: false 9 | workingDir: ${PROJECT_SOURCE} 10 | id: s2i-assemble 11 | - exec: 12 | commandLine: /usr/libexec/s2i/run 13 | component: s2i-builder 14 | group: 15 | isDefault: true 16 | kind: run 17 | hotReloadCapable: false 18 | workingDir: ${PROJECT_SOURCE} 19 | id: s2i-run 20 | components: 21 | - container: 22 | env: 23 | - name: KOPF_OPTIONS 24 | value: --debug --log-format=json 25 | - name: KOPF_PEERING 26 | value: babylon-catalog-manager-dev 27 | - name: LOGLEVEL 28 | value: debug 29 | image: quay.io/redhat-cop/python-kopf-s2i 30 | mountSources: true 31 | sourceMapping: /tmp/projects 32 | name: s2i-builder 33 | metadata: 34 | name: babylon-catalog-manager-dev 35 | version: 1.0.0 36 | schemaVersion: 2.0.0 37 | -------------------------------------------------------------------------------- /catalog-manager/helm/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: babylon-catalog-manager 3 | description: A Helm chart for the babylon catalog manager component. 4 | type: application 5 | version: 1.0.18 6 | appVersion: 1.0.18 7 | -------------------------------------------------------------------------------- /catalog-manager/helm/templates/gpte-db-secrets.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Values.db }} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: gpte-db-secrets 6 | namespace: {{ include "babylon-catalog-manager.namespaceName" . }} 7 | labels: 8 | {{- include "babylon-catalog-manager.labels" . | nindent 4 }} 9 | data: 10 | dbname: {{ required ".Values.db.name is required!" .Values.db.name | b64enc }} 11 | username: {{ required ".Values.db.username is required!" .Values.db.username | b64enc }} 12 | password: {{ required ".Values.db.password is required!" .Values.db.password | b64enc }} 13 | hostname: {{ required ".Values.db.hostname is required!" .Values.db.hostname | b64enc }} 14 | port: {{ required ".Values.db.port is required!" .Values.db.port | b64enc }} 15 | {{ end }} -------------------------------------------------------------------------------- /catalog-manager/helm/templates/namespace.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Values.namespace.create }} 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: {{ include "babylon-catalog-manager.namespaceName" . }} 6 | {{ end }} 7 | -------------------------------------------------------------------------------- /catalog-manager/helm/templates/salesforce-api-secret.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.salesforceApi.deploy }} 2 | apiVersion: bitwarden-k8s-secrets-manager.demo.redhat.com/v1 3 | kind: BitwardenSyncSecret 4 | metadata: 5 | name: {{ .Values.salesforceApi.secretName | default "babylon-catalog-manager-salesforce-api" }} 6 | namespace: {{ include "babylon-catalog-manager.namespaceName" . }} 7 | spec: 8 | data: 9 | salesforce-api-token: 10 | secret: salesforce_api_login_token 11 | key: service_token 12 | {{- end }} -------------------------------------------------------------------------------- /catalog-manager/helm/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Values.deploy }} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "babylon-catalog-manager.serviceAccountName" . }} 6 | namespace: {{ include "babylon-catalog-manager.namespaceName" . }} 7 | labels: 8 | {{- include "babylon-catalog-manager.labels" . | nindent 4 }} 9 | {{ end }} 10 | -------------------------------------------------------------------------------- /catalog-manager/kopf-opt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | KOPF_NAMESPACED=false 3 | -------------------------------------------------------------------------------- /catalog-manager/operator/configure_kopf_logging.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | 4 | def suppress_handler_succeeded_messages(record: logging.LogRecord) -> bool: 5 | txt = record.getMessage() 6 | if txt.startswith("Handler ") and txt.endswith(" succeeded."): 7 | return False 8 | return True 9 | 10 | 11 | def configure_kopf_logging(): 12 | objlogger = logging.getLogger("kopf.objects") 13 | objlogger.addFilter(suppress_handler_succeeded_messages) 14 | -------------------------------------------------------------------------------- /catalog-manager/operator/infinite_relative_backoff.py: -------------------------------------------------------------------------------- 1 | class InfiniteRelativeBackoff: 2 | def __init__(self, initial_delay=0.1, scaling_factor=2, maximum=60): 3 | self.initial_delay = initial_delay 4 | self.scaling_factor = scaling_factor 5 | self.maximum = maximum 6 | 7 | def __iter__(self): 8 | delay = self.initial_delay 9 | while True: 10 | if delay > self.maximum: 11 | yield self.maximum 12 | else: 13 | yield delay 14 | delay *= self.scaling_factor 15 | -------------------------------------------------------------------------------- /catalog-manager/operator/rating.py: -------------------------------------------------------------------------------- 1 | class Rating: 2 | def __init__(self, rating_score, total_ratings): 3 | self.rating_score = float(rating_score) if rating_score is not None else None 4 | self.total_ratings = int(total_ratings) 5 | 6 | def __eq__(self, rating): 7 | if isinstance(rating, Rating): 8 | return ( 9 | self.rating_score == rating.rating_score 10 | and self.total_ratings == rating.total_ratings 11 | ) 12 | return False 13 | -------------------------------------------------------------------------------- /catalog-manager/requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.10.11 2 | psycopg2==2.9.5 3 | retrying==1.3.4 -------------------------------------------------------------------------------- /catalog/README.adoc: -------------------------------------------------------------------------------- 1 | = Babylon Admin User Interface 2 | 3 | The Babylon admin user interface is composed of a Vue.js frontend and a Python flask API proxy to the OpenShift cluster UI. 4 | 5 | == Build 6 | 7 | A `Dockerfile` is provided which includes a two-stage build process which combines the build of the Vue.js UI and the Flask UI. 8 | -------------------------------------------------------------------------------- /catalog/api/Containerfile: -------------------------------------------------------------------------------- 1 | FROM registry.access.redhat.com/ubi9/python-312:latest 2 | 3 | USER 0 4 | COPY . /tmp/src 5 | RUN /usr/bin/fix-permissions /tmp/src 6 | USER 1001 7 | 8 | RUN /usr/libexec/s2i/assemble 9 | 10 | EXPOSE 8080 11 | 12 | CMD /usr/libexec/s2i/run 13 | -------------------------------------------------------------------------------- /catalog/api/README.adoc: -------------------------------------------------------------------------------- 1 | = Babylon Catalog API 2 | 3 | == Setup 4 | 5 | Initial setup to run once to prepare for running the API: 6 | 7 | ----------------------------------------------- 8 | python3 -m venv ~/virtualenv/babylon-catalog-api/ 9 | . ~/virtualenv/babylon-catalog-api/bin/activate 10 | pip install -r requirements.txt 11 | ----------------------------------------------- 12 | 13 | === Running in Development 14 | 15 | Commands each time to start: 16 | 17 | Login with `oc`, then start the local development server. 18 | 19 | --------------------------------- 20 | . ~/virtualenv/babylon-catalog-api/bin/activate 21 | export BABYLON_NAMESPACE=babylon-catalog 22 | export ENVIRONMENT=development 23 | export INTERFACE_NAME=rhpds 24 | python3 app.py 25 | --------------------------------- 26 | 27 | The ReactJS user interface is configured to proxy requests to the server on port 5000. 28 | -------------------------------------------------------------------------------- /catalog/api/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | workers = int(os.environ.get('GUNICORN_PROCESSES', '3')) 4 | threads = int(os.environ.get('GUNICORN_THREADS', '1')) 5 | 6 | forwarded_allow_ips = '*' 7 | secure_scheme_headers = { 'X-Forwarded-Proto': 'https' } 8 | -------------------------------------------------------------------------------- /catalog/api/randomstring.py: -------------------------------------------------------------------------------- 1 | import random 2 | import string 3 | 4 | def random_string(length): 5 | return ''.join([random.choice(string.ascii_letters + string.digits) for n in range(length)]) 6 | -------------------------------------------------------------------------------- /catalog/api/requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.10.11 2 | kubernetes_asyncio==29.0.0 3 | redis==5.0.4 4 | -------------------------------------------------------------------------------- /catalog/babylon-catalog.route.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: route.openshift.io/v1 2 | kind: Route 3 | metadata: 4 | labels: 5 | app.kubernetes.io/managed-by: Helm 6 | app.kubernetes.io/name: babylon-catalog 7 | app.kubernetes.io/version: 0.0.1 8 | helm.sh/chart: babylonCatalog-0.0.1 9 | name: babylon-catalog 10 | namespace: babylon 11 | spec: 12 | host: babylon-catalog-babylon.apps.babydev.dev.open.redhat.com 13 | tls: 14 | insecureEdgeTerminationPolicy: Redirect 15 | termination: reencrypt 16 | to: 17 | kind: Service 18 | name: babylon-catalog-oauth-proxy 19 | weight: 100 20 | wildcardPolicy: None 21 | -------------------------------------------------------------------------------- /catalog/helm/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: babylonCatalog 4 | description: Babylon Catalog UI 5 | type: application 6 | version: 0.0.1 7 | appVersion: 0.0.1 8 | -------------------------------------------------------------------------------- /catalog/helm/templates/access/clusterrole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: {{ printf "%s-access" (include "babylonCatalog.name" .) }} 5 | labels: 6 | {{- include "babylonCatalog.labels" . | nindent 4 }} 7 | rules: 8 | - apiGroups: 9 | - babylon.gpte.redhat.com 10 | resources: 11 | - catalogitems 12 | verbs: 13 | - get 14 | - list 15 | - watch 16 | -------------------------------------------------------------------------------- /catalog/helm/templates/api/clusterrole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: {{ include "babylonCatalog.apiClusterRoleName" . }} 5 | labels: 6 | {{- include "babylonCatalog.labels" . | nindent 4 }} 7 | rules: 8 | - apiGroups: 9 | - "" 10 | - user.openshift.io 11 | resources: 12 | - groups 13 | - users 14 | verbs: 15 | - get 16 | - impersonate 17 | - list 18 | - apiGroups: 19 | - "" 20 | resources: 21 | - namespaces 22 | - secrets 23 | verbs: 24 | - get 25 | - list 26 | - apiGroups: 27 | - babylon.gpte.redhat.com 28 | resources: 29 | - workshops 30 | verbs: 31 | - get 32 | - list 33 | - patch 34 | - watch 35 | - update 36 | -------------------------------------------------------------------------------- /catalog/helm/templates/api/clusterrolebinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: {{ include "babylonCatalog.apiClusterRoleBindingName" . }} 5 | labels: 6 | {{- include "babylonCatalog.labels" . | nindent 4 }} 7 | roleRef: 8 | apiGroup: rbac.authorization.k8s.io 9 | kind: ClusterRole 10 | name: {{ include "babylonCatalog.apiClusterRoleName" . }} 11 | subjects: 12 | - kind: ServiceAccount 13 | name: {{ include "babylonCatalog.apiServiceAccountName" . }} 14 | namespace: {{ include "babylonCatalog.namespaceName" . }} 15 | -------------------------------------------------------------------------------- /catalog/helm/templates/api/salesforce-api-secret.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.salesforceApi.deploy }} 2 | apiVersion: bitwarden-k8s-secrets-manager.demo.redhat.com/v1 3 | kind: BitwardenSyncSecret 4 | metadata: 5 | name: {{ .Values.salesforceApi.secretName | default "babylon-catalog-salesforce-api" }} 6 | namespace: {{ include "babylonCatalog.namespaceName" . }} 7 | spec: 8 | data: 9 | salesforce-api-token: 10 | secret: salesforce_api_login_token 11 | key: service_token 12 | {{- end }} -------------------------------------------------------------------------------- /catalog/helm/templates/api/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "babylonCatalog.apiName" . }} 5 | namespace: {{ include "babylonCatalog.namespaceName" . }} 6 | labels: 7 | {{- include "babylonCatalog.labels" . | nindent 4 }} 8 | spec: 9 | ports: 10 | - name: api 11 | port: 8080 12 | protocol: TCP 13 | targetPort: 8080 14 | selector: 15 | {{- include "babylonCatalog.apiSelectorLabels" . | nindent 4 }} 16 | type: ClusterIP 17 | -------------------------------------------------------------------------------- /catalog/helm/templates/api/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: {{ include "babylonCatalog.apiName" . }} 5 | namespace: {{ include "babylonCatalog.namespaceName" . }} 6 | labels: 7 | {{- include "babylonCatalog.labels" . | nindent 4 }} 8 | -------------------------------------------------------------------------------- /catalog/helm/templates/namespace.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.namespace.create -}} 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: {{ include "babylonCatalog.namespaceName" . }} 6 | labels: 7 | {{- include "babylonCatalog.labels" . | nindent 4 }} 8 | {{- end -}} 9 | -------------------------------------------------------------------------------- /catalog/helm/templates/oauth-proxy/clientSecret.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.oauthProxy.clientSecret }} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ include "babylonCatalog.oauthProxyClientSecretName" . }} 6 | namespace: {{ include "babylonCatalog.namespaceName" . }} 7 | labels: 8 | {{- include "babylonCatalog.labels" . | nindent 4 }} 9 | data: 10 | clientSecret: {{ .Values.oauthProxy.clientSecret | b64enc }} 11 | {{- end }} 12 | -------------------------------------------------------------------------------- /catalog/helm/templates/oauth-proxy/cookieSecret.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.oauthProxy.cookieSecret }} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ include "babylonCatalog.oauthProxyCookieSecretName" . }} 6 | namespace: {{ include "babylonCatalog.namespaceName" . }} 7 | labels: 8 | {{- include "babylonCatalog.labels" . | nindent 4 }} 9 | data: 10 | cookieSecret: {{ .Values.oauthProxy.cookieSecret | b64enc }} 11 | {{- end }} 12 | -------------------------------------------------------------------------------- /catalog/helm/templates/oauth-proxy/oauthclient.yaml: -------------------------------------------------------------------------------- 1 | {{- if (and .Values.oauthProxy.clientSecret .Values.route.host) }} 2 | apiVersion: oauth.openshift.io/v1 3 | kind: OAuthClient 4 | metadata: 5 | name: {{ include "babylonCatalog.namespaceName" . }} 6 | grantMethod: auto 7 | redirectURIs: 8 | - https://{{ .Values.route.host }}/oauth/callback 9 | secret: {{ .Values.oauthProxy.clientSecret }} 10 | {{- end }} 11 | -------------------------------------------------------------------------------- /catalog/helm/templates/oauth-proxy/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "babylonCatalog.oauthProxyName" . }} 5 | namespace: {{ include "babylonCatalog.namespaceName" . }} 6 | annotations: 7 | service.alpha.openshift.io/serving-cert-secret-name: {{ printf "%s-tls" (include "babylonCatalog.oauthProxyName" .) }} 8 | labels: 9 | {{- include "babylonCatalog.labels" . | nindent 4 }} 10 | spec: 11 | ports: 12 | - name: proxy 13 | port: 443 14 | protocol: TCP 15 | targetPort: 8443 16 | selector: 17 | {{- include "babylonCatalog.oauthProxySelectorLabels" . | nindent 4 }} 18 | type: ClusterIP 19 | -------------------------------------------------------------------------------- /catalog/helm/templates/oauth-proxy/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: {{ include "babylonCatalog.oauthProxyName" . }} 5 | namespace: {{ include "babylonCatalog.namespaceName" . }} 6 | annotations: 7 | serviceaccounts.openshift.io/oauth-redirectreference.primary: >- 8 | {"kind":"OAuthRedirectReference","apiVersion":"v1","reference":{"kind":"Route","name":{{ (include "babylonCatalog.name" .) | quote }}}} 9 | labels: 10 | {{- include "babylonCatalog.labels" . | nindent 4 }} 11 | -------------------------------------------------------------------------------- /catalog/helm/templates/redis/secret.yaml: -------------------------------------------------------------------------------- 1 | {{- if (or .Values.redis.password .Values.redis.generatePassword) }} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ include "babylonCatalog.redisName" . }} 6 | namespace: {{ include "babylonCatalog.namespaceName" . }} 7 | labels: 8 | {{- include "babylonCatalog.labels" . | nindent 4 }} 9 | data: 10 | {{- if .Values.redis.password }} 11 | database-password: {{ .Values.redis.password | b64enc }} 12 | {{- else }} 13 | database-password: {{ randAlphaNum 32 | b64enc }} 14 | {{- end }} 15 | {{- end }} 16 | -------------------------------------------------------------------------------- /catalog/helm/templates/redis/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "babylonCatalog.redisName" . }} 5 | namespace: {{ include "babylonCatalog.namespaceName" . }} 6 | labels: 7 | {{- include "babylonCatalog.labels" . | nindent 4 }} 8 | spec: 9 | type: ClusterIP 10 | ports: 11 | - name: redis 12 | port: 6379 13 | protocol: TCP 14 | targetPort: 6379 15 | selector: 16 | {{- include "babylonCatalog.redisSelectorLabels" . | nindent 4 }} 17 | -------------------------------------------------------------------------------- /catalog/helm/templates/status/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "babylonCatalog.statusName" . }} 5 | namespace: {{ include "babylonCatalog.namespaceName" . }} 6 | labels: 7 | {{- include "babylonCatalog.labels" . | nindent 4 }} 8 | spec: 9 | ports: 10 | - name: proxy 11 | port: 8080 12 | protocol: TCP 13 | targetPort: 8080 14 | selector: 15 | {{- include "babylonCatalog.statusSelectorLabels" . | nindent 4 }} 16 | type: ClusterIP 17 | -------------------------------------------------------------------------------- /catalog/helm/templates/ui/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "babylonCatalog.uiName" . }} 5 | namespace: {{ include "babylonCatalog.namespaceName" . }} 6 | labels: 7 | {{- include "babylonCatalog.labels" . | nindent 4 }} 8 | spec: 9 | ports: 10 | - name: proxy 11 | port: 8080 12 | protocol: TCP 13 | targetPort: 8080 14 | selector: 15 | {{- include "babylonCatalog.uiSelectorLabels" . | nindent 4 }} 16 | type: ClusterIP 17 | -------------------------------------------------------------------------------- /catalog/jmeter/example.csv: -------------------------------------------------------------------------------- 1 | username,password 2 | -------------------------------------------------------------------------------- /catalog/status/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.access.redhat.com/ubi9/nginx-120 2 | 3 | # Add application sources to a directory that the assemble script expects them 4 | # and set permissions so that the container runs without root access 5 | USER root 6 | 7 | ADD nginx-default-cfg/redirect.conf "${NGINX_DEFAULT_CONF_PATH}" 8 | ADD *.html . 9 | ADD *.css . 10 | ADD *.js . 11 | COPY assets ./assets 12 | COPY interfaces ./interfaces 13 | 14 | USER 1001 15 | 16 | EXPOSE 8080 17 | 18 | # Run script uses standard ways to run the application 19 | CMD nginx -g "daemon off;" 20 | -------------------------------------------------------------------------------- /catalog/status/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-cop/babylon/1305b9218a0d3da08c8586f194903434f1b9f13e/catalog/status/assets/favicon.ico -------------------------------------------------------------------------------- /catalog/status/interfaces/rhdp-partners.json: -------------------------------------------------------------------------------- 1 | { 2 | "incidents_enabled": true, 3 | "ratings_enabled": true, 4 | "status_page_url": "https://rhdp-partner.statuspage.io/", 5 | "status_page_id": "j70k6yk8v2pk", 6 | "help_text": "Partner Help Desk", 7 | "help_link": "https://connect.redhat.com/en/support", 8 | "internal_help_link": "https://connect.redhat.com/en/support", 9 | "feedback_link": "https://forms.gle/qBBWtXMea8vDqZUu7", 10 | "learn_more_link": "https://content.redhat.com/content/rhcc/us/en/product/cross-portfolio-initiatives/rhdp.html" 11 | } -------------------------------------------------------------------------------- /catalog/status/interfaces/rhpds.json: -------------------------------------------------------------------------------- 1 | { 2 | "incidents_enabled": true, 3 | "ratings_enabled": true, 4 | "status_page_url": "https://rhdp.statuspage.io/", 5 | "status_page_id": "05mhm9ljgsqq", 6 | "help_text": "Open Support Case", 7 | "help_link": "https://red.ht/open-support", 8 | "internal_help_link": "https://red.ht/demo-help", 9 | "feedback_link": "https://docs.google.com/forms/d/e/1FAIpQLSfwGW7ql2lDfaLDpg4Bgj_puFEVsM0El6-Nz8fyH48RnGLDrA/viewform?usp=sf_link", 10 | "learn_more_link": "https://content.redhat.com/us/en/product/cross-portfolio-initiatives/rhdp.html" 11 | } -------------------------------------------------------------------------------- /catalog/status/nginx-default-cfg/redirect.conf: -------------------------------------------------------------------------------- 1 | location ~* \.(?:css|js|json)$ { 2 | rewrite ^/status/(.*) /$1 break; 3 | try_files $uri =404; 4 | access_log off; 5 | add_header Cache-Control "public"; 6 | expires 1y; 7 | } 8 | # Any route that doesn't have a file extension (e.g. /devices) 9 | location / { 10 | add_header Cache-Control "max-age=0, no-cache, no-store, must-revalidate"; 11 | add_header Pragma "no-cache"; 12 | add_header Last-Modified $date_gmt; 13 | etag off; 14 | if_modified_since off; 15 | expires off; 16 | try_files $uri $uri/ /index.html; 17 | } -------------------------------------------------------------------------------- /catalog/ui/.dockerignore: -------------------------------------------------------------------------------- 1 | .storybook 2 | __mocks__ 3 | stories 4 | .git 5 | Dockerfile 6 | .dockerignore 7 | .gitignore 8 | README.md 9 | dist 10 | npm-debug.log 11 | node_modules 12 | .env 13 | -------------------------------------------------------------------------------- /catalog/ui/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.snap] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | 15 | [*.md] 16 | max_line_length = off 17 | trim_trailing_whitespace = false 18 | -------------------------------------------------------------------------------- /catalog/ui/.gitignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | dist 3 | yarn-error.log 4 | stats.json 5 | coverage 6 | storybook-static 7 | .DS_Store 8 | .idea 9 | .env 10 | -------------------------------------------------------------------------------- /catalog/ui/.prettierignore: -------------------------------------------------------------------------------- 1 | package.json 2 | node_modules 3 | coverage 4 | -------------------------------------------------------------------------------- /catalog/ui/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "printWidth": 120 4 | } 5 | -------------------------------------------------------------------------------- /catalog/ui/Dockerfile: -------------------------------------------------------------------------------- 1 | # Keep assets from the previous release that are less than 3 months older 2 | FROM quay.io/redhat-gpte/babylon-catalog-ui:latest AS previous 3 | USER root 4 | WORKDIR /tmp 5 | RUN rm -rf ./previous && mv ./src/ ./previous 6 | RUN touch -t $(date -d "-3 months" +'%Y%m%d0000') ./timestamp 7 | RUN find ./previous -type f ! -newer ./timestamp -exec rm {} \; 8 | 9 | # Builder image 10 | FROM registry.redhat.io/rhel9/nodejs-20-minimal:latest AS builder 11 | USER root 12 | WORKDIR /build 13 | 14 | ARG MONITOR_ENABLED 15 | ARG TRACKING_ENABLED 16 | ARG OPTIONAL_FLAGS 17 | 18 | COPY --from=previous /tmp/previous ./dist 19 | 20 | ENV KEEP_ASSETS=true 21 | COPY package.json package-lock.json ./ 22 | RUN npm ci && npm cache clean --force 23 | COPY ./ ./ 24 | RUN npm run build 25 | 26 | # Server image 27 | FROM registry.access.redhat.com/ubi8/nginx-118:latest 28 | USER root 29 | 30 | COPY --from=builder /build/dist /tmp/src 31 | COPY nginx-default-cfg /tmp/src/nginx-default-cfg 32 | 33 | RUN chown -R 1001:0 /tmp/src && \ 34 | chmod -R g+w /tmp/src 35 | USER 1001 36 | RUN /usr/libexec/s2i/assemble 37 | 38 | EXPOSE 8080 39 | CMD /usr/libexec/s2i/run 40 | -------------------------------------------------------------------------------- /catalog/ui/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Red Hat 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /catalog/ui/__mocks__/fileMock.js: -------------------------------------------------------------------------------- 1 | module.exports = 'test-file-stub'; 2 | -------------------------------------------------------------------------------- /catalog/ui/__mocks__/styleMock.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /catalog/ui/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@babel/preset-typescript', '@babel/preset-env', '@babel/preset-react'], 3 | plugins: [ 4 | [ 5 | 'transform-imports', 6 | { 7 | '@patternfly/react-icons': { 8 | transform: (importName, matches) => 9 | `@patternfly/react-icons/dist/js/icons/${importName 10 | .split(/(?=[A-Z])/) 11 | .join('-') 12 | .toLowerCase()}`, 13 | preventFullImport: true, 14 | }, 15 | }, 16 | ], 17 | ], 18 | }; 19 | -------------------------------------------------------------------------------- /catalog/ui/dr-surge.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const indexPath = path.resolve(__dirname, 'dist/index.html'); 4 | const targetFilePath = path.resolve(__dirname, 'dist/200.html'); 5 | // ensure we have bookmarkable url's when publishing to surge 6 | // https://surge.sh/help/adding-a-200-page-for-client-side-routing 7 | fs.createReadStream(indexPath).pipe(fs.createWriteStream(targetFilePath)); 8 | -------------------------------------------------------------------------------- /catalog/ui/nginx-default-cfg/redirect.conf: -------------------------------------------------------------------------------- 1 | location ~* \.(?:css|js)$ { 2 | try_files $uri =404; 3 | access_log off; 4 | add_header Cache-Control "public"; 5 | expires 1y; 6 | gzip on; 7 | gzip_types text/css application/javascript; 8 | gzip_comp_level 6; 9 | gzip_vary on; 10 | } 11 | 12 | # Any route that doesn't have a file extension (e.g. /devices) 13 | location / { 14 | add_header Cache-Control "max-age=0, no-cache, no-store, must-revalidate"; 15 | add_header Pragma "no-cache"; 16 | add_header Last-Modified $date_gmt; 17 | etag off; 18 | if_modified_since off; 19 | expires off; 20 | try_files $uri $uri/ /index.html; 21 | gzip on; 22 | gzip_types text/html application/xhtml+xml application/xml; 23 | gzip_comp_level 6; 24 | gzip_vary on; 25 | } 26 | 27 | gzip_disable "msie6"; 28 | gzip_proxied any; 29 | gzip_buffers 16 8k; 30 | gzip_http_version 1.1; 31 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Admin/RatingsPage.tsx: -------------------------------------------------------------------------------- 1 | import React, { Suspense } from 'react'; 2 | import { PageSection, PageSectionVariants, Split, SplitItem, Title } from '@patternfly/react-core'; 3 | import RatingsList from './RatingsList'; 4 | import LoadingSection from '@app/components/LoadingSection'; 5 | 6 | import './admin.css'; 7 | 8 | const RatingsPage: React.FC = () => { 9 | return ( 10 | <> 11 | 12 | 13 | 14 | 15 | Ratings 16 | 17 | 18 | 19 | 20 | 21 | }> 22 | 23 | 24 | 25 | 26 | ); 27 | }; 28 | 29 | export default RatingsPage; 30 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Catalog/CatalogItemHealthDisplay.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const CatalogItemHealthDisplay: React.FunctionComponent<{ 4 | provisionHistory: { result?: string }[]; 5 | }> = ({ provisionHistory }) => { 6 | return ( 7 |
16 | {provisionHistory.map((provision, idx) => { 17 | if (provision.result === 'success') { 18 | return
; 19 | } else { 20 | return
; 21 | } 22 | })} 23 |
24 | ); 25 | }; 26 | 27 | export default CatalogItemHealthDisplay; 28 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Catalog/CatalogItemIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PackageIcon from '@patternfly/react-icons/dist/js/icons/package-icon'; 3 | import { CatalogItem } from '@app/types'; 4 | 5 | const CatalogItemIcon: React.FC<{ 6 | catalogItem: CatalogItem; 7 | }> = ({ catalogItem }) => { 8 | const iconConfig = catalogItem.spec.icon; 9 | 10 | if (iconConfig) { 11 | try { 12 | if (iconConfig.url) 13 | return {iconConfig.alt}; 14 | } catch (_) { 15 | // 16 | } 17 | } 18 | 19 | return ; 20 | }; 21 | 22 | export default CatalogItemIcon; 23 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Catalog/catalog-category-selector.css: -------------------------------------------------------------------------------- 1 | .catalog-category-selector { 2 | margin-bottom: var(--pf-v5-global--spacer--md) !important; 3 | } 4 | 5 | .catalog-category-selector .pf-v5-c-tabs__item.pf-m-current .pf-v5-c-tabs__item-text { 6 | color: var(--pf-v5-global--link--Color); 7 | } 8 | 9 | .catalog-category-selector .pf-v5-c-tabs__item-text { 10 | color: var(--pf-v5-global--palette--black-800); 11 | } 12 | 13 | .catalog-category-selector .pf-v5-c-tabs__item:first-child { 14 | margin-bottom: var(--pf-v5-global--spacer--md); 15 | } 16 | 17 | .catalog-category-selector .pf-v5-c-tabs__item .pf-v5-c-tabs__link { 18 | padding: 0 var(--pf-v5-global--spacer--md); 19 | } 20 | 21 | .catalog-category-selector .pf-v5-c-tabs__scroll-button { 22 | display: none; 23 | } 24 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Catalog/catalog-item-workshop-form.css: -------------------------------------------------------------------------------- 1 | .catalog-item-workshop-form-title.pf-v5-c-page__main-section { 2 | border-bottom: 1px solid var(--pf-v5-global--palette--black-300); 3 | } 4 | 5 | .catalog-item-workshop-form-parameters.pf-v5-c-page__main-section { 6 | border-bottom: 1px solid var(--pf-v5-global--palette--black-300); 7 | } 8 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Catalog/catalog-namespace-select.css: -------------------------------------------------------------------------------- 1 | .catalog-namespace-select { 2 | padding: var(--pf-v5-global--spacer--xs) var(--pf-v5-global--spacer--md) !important; 3 | border-bottom: 1px solid var(--pf-v5-global--palette--black-300); 4 | display: flex; 5 | } 6 | 7 | .catalog-namespace-select .pf-c-dropdown__toggle { 8 | color: var(--pf-v5-global--palette--black-900); 9 | } 10 | 11 | .catalog-namespace-select .pf-c-dropdown__menu { 12 | max-height: 500px; 13 | overflow-y: scroll; 14 | } 15 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Catalog/icons/openshift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-cop/babylon/1305b9218a0d3da08c8586f194903434f1b9f13e/catalog/ui/src/app/Catalog/icons/openshift.png -------------------------------------------------------------------------------- /catalog/ui/src/app/Dashboard/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Navigate } from 'react-router-dom'; 3 | 4 | const Dashboard: React.FC = () => ; 5 | 6 | export default Dashboard; 7 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Header/header.css: -------------------------------------------------------------------------------- 1 | .header-component .pf-v5-c-app-launcher__menu-item-external-icon { 2 | opacity: 1; 3 | color: var(--pf-v5-c-app-launcher__menu-item--Color); 4 | } 5 | .header-component__user-controls button::before { 6 | border: none; 7 | } 8 | 9 | .header-component__user-controls--warning .pf-v5-c-dropdown__toggle-text { 10 | color: #ee0000; 11 | font-weight: bold; 12 | } 13 | 14 | @media (--small-viewport) { 15 | .header-component.pf-v5-c-page__header { 16 | grid-template-columns: 1fr 0; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Modal/Modal.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, renderHook } from '@testing-library/react'; 3 | import Modal, { useModal } from './Modal'; 4 | 5 | describe('Modal tests', () => { 6 | it('should render inside #modal-root', () => { 7 | const { result } = renderHook(() => useModal()); 8 | const [modalRef] = result.current; 9 | const { container } = render( 10 |
11 | null} ref={modalRef}> 12 |

My Content

13 |
14 | , 16 | ); 17 | expect(container.querySelector('#modal-root')).toBeInTheDocument(); 18 | expect(container.innerText).toBeFalsy(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Modal/modal.css: -------------------------------------------------------------------------------- 1 | .modal-component.pf-v5-c-modal-box .pf-v5-c-modal-box__title-text { 2 | white-space: normal; 3 | font-size: var(--pf-v5-global--icon--FontSize--md); 4 | } 5 | 6 | .modal-component.pf-v5-c-modal-box .pf-v5-c-modal-box__body { 7 | overflow-x: visible; 8 | overflow-y: visible; 9 | } 10 | 11 | .modal-component.pf-v5-c-modal-box .pf-c-dropdown__menu { 12 | max-height: 300px; 13 | } 14 | 15 | .modal-component.pf-v5-c-modal-box .pf-v5-c-form__group-label { 16 | text-transform: capitalize; 17 | } 18 | 19 | .modal-component.pf-v5-c-modal-box .pf-v5-c-form.pf-m-horizontal .pf-v5-c-form__group { 20 | grid-template-columns: none; 21 | } 22 | 23 | @media (--small-viewport) { 24 | .pf-v5-c-backdrop__open .pf-v5-c-backdrop { 25 | max-width: 100vw; 26 | } 27 | .modal-component.pf-v5-c-modal-box { 28 | margin-bottom: auto; 29 | margin-top: 120px; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Modal/useModal.tsx: -------------------------------------------------------------------------------- 1 | import { useRef } from 'react'; 2 | 3 | export default function useModal(): [ 4 | modalInstance: React.Ref<{ 5 | open: () => void; 6 | close: () => void; 7 | }>, 8 | openModalFn: () => void, 9 | closeModalFn: () => void, 10 | ] { 11 | const modalInstance = useRef(null); 12 | 13 | const openModalFn = () => { 14 | modalInstance.current.open(); 15 | }; 16 | 17 | const closeModalFn = () => { 18 | modalInstance.current.close(); 19 | }; 20 | 21 | return [modalInstance, openModalFn, closeModalFn]; 22 | } 23 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Services/Services.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useParams } from 'react-router-dom'; 3 | 4 | const ServicesItem = React.lazy(() => import('@app/Services/ServicesItem')); 5 | const ServicesList = React.lazy(() => import('@app/Services/ServicesList')); 6 | 7 | const Services: React.FC = () => { 8 | const { namespace, name, tab } = useParams(); 9 | if (name) { 10 | return ; 11 | } 12 | return ; 13 | }; 14 | 15 | export default Services; 16 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Services/service-item-status.css: -------------------------------------------------------------------------------- 1 | .services-item-status__header.pf-l-split .pf-v5-c-description-list.pf-m-horizontal { 2 | padding-top: 0.5em; 3 | } 4 | 5 | .services-item-status__header.pf-l-split .services-item-status-check-state { 6 | padding-top: 0.3em; 7 | } 8 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Services/service-status.css: -------------------------------------------------------------------------------- 1 | .service-status--available { 2 | color: var(--pf-v5-global--success-color--100); 3 | } 4 | 5 | .service-status--failed { 6 | color: var(--pf-v5-global--danger-color--100); 7 | text-transform: capitalize; 8 | } 9 | 10 | .service-status--running { 11 | color: var(--pf-v5-global--success-color--100); 12 | } 13 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Services/services-delete-modal.css: -------------------------------------------------------------------------------- 1 | .services-delete-modal .pf-v5-c-modal-box__title-text { 2 | white-space: normal; 3 | font-size: 0.9em; 4 | } 5 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Services/services-schedule-action-modal.css: -------------------------------------------------------------------------------- 1 | .services-schedule-action-modal.pf-v5-c-modal-box .pf-v5-c-modal-box__title-text { 2 | white-space: normal; 3 | font-size: 0.9em; 4 | } 5 | 6 | .services-schedule-action-modal.pf-v5-c-modal-box .pf-v5-c-modal-box__body { 7 | overflow-x: visible; 8 | overflow-y: visible; 9 | } 10 | 11 | .services-schedule-action-modal.pf-v5-c-modal-box .pf-c-dropdown__menu { 12 | max-height: 300px; 13 | } 14 | 15 | .services-schedule-action-modal.pf-v5-c-modal-box .pf-v5-c-form__group-label { 16 | text-transform: capitalize; 17 | } 18 | 19 | .services-schedule-action-modal.pf-v5-c-modal-box .pf-v5-c-form.pf-m-horizontal .pf-v5-c-form__group { 20 | grid-template-columns: none; 21 | } 22 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Support/support-page.css: -------------------------------------------------------------------------------- 1 | .support-page { 2 | padding: 0; 3 | } 4 | .support-page > * { 5 | padding: 0 6 | var(--pf-v5-c-page__main-section--PaddingR--pf-v5-pf-v5-pf-v5-pf-v5-pf-v5-c-page__main-section--PaddingLeft); 7 | } 8 | .support-page > *:last-child { 9 | padding-bottom: var(--pf-v5-c-page__main-section--PaddingBottom); 10 | } 11 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Workshop/workshop-content.css: -------------------------------------------------------------------------------- 1 | .workshop-content .pf-v5-c-description-list__group { 2 | padding: var(--pf-v5-global--spacer--md); 3 | background-color: var(--pf-v5-global--palette--white); 4 | border-radius: 4px; 5 | box-shadow: 6 | 0 1px 5px 0 rgb(3 3 3 / 12%), 7 | 0 0 1px 0 rgb(3 3 3 / 6%); 8 | } 9 | .workshop-content__title, 10 | .workshop-content__description { 11 | text-align: center; 12 | padding-bottom: var(--pf-v5-global--spacer--md); 13 | line-height: 1; 14 | } 15 | .workshop-content__wrapper { 16 | width: 1100px; 17 | height: auto; 18 | margin: 0 auto var(--pf-v5-global--spacer--xl); 19 | padding: var(--pf-v5-global--spacer--lg) var(--pf-v5-global--spacer--md); 20 | } 21 | .workshop-conte--pf-v5-rapper pre { 22 | font-family: var(--pf-v5-global--FontFamily--sans-serif); 23 | } 24 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Workshop/workshop-utils.ts: -------------------------------------------------------------------------------- 1 | export const apiPaths = { 2 | WORKSHOP: ({ workshopId }: { workshopId: string }): string => `/api/workshop/${workshopId}`, 3 | }; 4 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Workshop/workshop.css: -------------------------------------------------------------------------------- 1 | .workshop.pf-v5-c-page__header .pf-v5-c-page__header-brand { 2 | height: 60px; 3 | } 4 | .workshop .pf-v5-c-page__main, 5 | .workshop .pf-v5-c-page__main-section.pf-m-light { 6 | background-color: transparent !important; 7 | } 8 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Workshops/workshops-item-details.css: -------------------------------------------------------------------------------- 1 | .workshops-item-details__status--running, 2 | .workshops-item-details__status--scheduled { 3 | color: var(--pf-v5-global--success-color--100); 4 | } 5 | .workshops-item-details.pf-v5-c-description-list[class*='pf-m-horizontal'] { 6 | --pf-v5-c-description-list__term--width: 142px !important; 7 | } 8 | -------------------------------------------------------------------------------- /catalog/ui/src/app/Workshops/workshops-item-services.css: -------------------------------------------------------------------------------- 1 | .workshops-item-services__actions .pf-v5-c-button.pf-m-plain { 2 | margin: 0 0 0 0 !important; 3 | } 4 | -------------------------------------------------------------------------------- /catalog/ui/src/app/__mocks__/catalogItemIncident.json: -------------------------------------------------------------------------------- 1 | { 2 | "created_by": "string", 3 | "disabled": true, 4 | "status": "Under maintenance", 5 | "incident_url": "https://status-page.io", 6 | "jira_url": "GPTEINFRA-123", 7 | "comments": "[]", 8 | "asset_uuid": "c8a5d5ab-1b17-4c6a-866a-fe60de5482b4", 9 | "stage": "prod", 10 | "active": false, 11 | "created_at": "2024-09-18T11:30:54.558Z", 12 | "downtime_interval": "string", 13 | "downtime_hours": 0, 14 | "last_incident_at": "2024-09-18T11:30:54.558Z", 15 | "resolved_at": "2024-09-18T11:30:54.558Z", 16 | "uptime_interval": "string", 17 | "uptime_hours": 0, 18 | "updated_at": "2024-09-18T11:30:54.558Z", 19 | "id": 0 20 | } -------------------------------------------------------------------------------- /catalog/ui/src/app/bgimages/external-link.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /catalog/ui/src/app/bgimages/hero-img.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-cop/babylon/1305b9218a0d3da08c8586f194903434f1b9f13e/catalog/ui/src/app/bgimages/hero-img.jpeg -------------------------------------------------------------------------------- /catalog/ui/src/app/bgimages/openshift-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/AdocWrapper.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import './adoc-wrapper.css'; 4 | 5 | const AdocWrapper: React.FC<{ 6 | html: string; 7 | }> = ({ html }) => { 8 | return ( 9 |
15 | ); 16 | }; 17 | 18 | export default AdocWrapper; 19 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/ButtonCircleIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Tooltip, ButtonProps } from '@patternfly/react-core'; 3 | import { SVGIconProps } from '@patternfly/react-icons/dist/js/createIcon'; 4 | 5 | import './button-circle-icon.css'; 6 | 7 | const ButtonCircleIcon: React.FC< 8 | Omit & { 9 | icon: React.ComponentClass; 10 | description: string; 11 | } 12 | > = ({ icon, isDisabled = false, description, onClick, ...rest }) => { 13 | const Icon = icon; 14 | return ( 15 | 16 | 26 | 27 | ); 28 | }; 29 | 30 | export default ButtonCircleIcon; 31 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/ConditionalWrapper.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | type ConditionalWrapperProps = { 4 | children: JSX.Element; 5 | condition: boolean; 6 | wrapper: (children: JSX.Element) => JSX.Element; 7 | }; 8 | const ConditionalWrapper: React.FC = ({ condition, wrapper, children }) => 9 | condition ? React.cloneElement(wrapper(children)) : children; 10 | 11 | export default ConditionalWrapper; 12 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/CurrencyAmount.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const CurrencyAmount: React.FC<{ amount: number }> = ({ amount }) => { 4 | const _amount = (Math.ceil(amount * 100) / 100).toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'); 5 | return $ {_amount}; 6 | }; 7 | 8 | export default CurrencyAmount; 9 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/emoji/1F600.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-cop/babylon/1305b9218a0d3da08c8586f194903434f1b9f13e/catalog/ui/src/app/components/Editor/images/emoji/1F600.png -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/emoji/1F641.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-cop/babylon/1305b9218a0d3da08c8586f194903434f1b9f13e/catalog/ui/src/app/components/Editor/images/emoji/1F641.png -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/emoji/1F642.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-cop/babylon/1305b9218a0d3da08c8586f194903434f1b9f13e/catalog/ui/src/app/components/Editor/images/emoji/1F642.png -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/emoji/2764.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-cop/babylon/1305b9218a0d3da08c8586f194903434f1b9f13e/catalog/ui/src/app/components/Editor/images/emoji/2764.png -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/emoji/LICENSE.md: -------------------------------------------------------------------------------- 1 | OpenMoji 2 | https://openmoji.org 3 | 4 | Licensed under Attribution-ShareAlike 4.0 International 5 | https://creativecommons.org/licenses/by-sa/4.0/ 6 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/LICENSE.md: -------------------------------------------------------------------------------- 1 | Bootstrap Icons 2 | https://icons.getbootstrap.com 3 | 4 | Licensed under MIT license 5 | https://github.com/twbs/icons/blob/main/LICENSE.md 6 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/arrow-clockwise.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/arrow-counterclockwise.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/chat-square-quote.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/chevron-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/code.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/journal-code.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/journal-text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/justify.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/list-ol.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/list-ul.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/pencil-fill.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/text-center.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/text-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/text-paragraph.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/text-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/type-bold.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/type-h1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/type-h2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/type-h3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/type-italic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/type-strikethrough.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/Editor/images/icons/type-underline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /catalog/ui/src/app/components/ErrorBoundaryPage.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import UnexpectedError from './UnexpectedError'; 3 | import { ErrorBoundary } from 'react-error-boundary'; 4 | import Footer from './Footer'; 5 | import NotFoundComponent from './NotFound'; 6 | 7 | const ErrorBoundaryPage: React.FC<{ 8 | name: string; 9 | namespace?: string; 10 | type: string; 11 | includeFooter?: boolean; 12 | children: React.ReactNode; 13 | }> = ({ name, namespace, type, includeFooter = true, children }) => ( 14 | window['newrelic'] && window['newrelic'].noticeError(err)} 16 | fallbackRender={({ error }: { error: any }) => ( 17 | <> 18 | {error?.status === 404 ? ( 19 | 20 | ) : ( 21 | 22 | )} 23 | {includeFooter ?