├── .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
;
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 |
15 |
,
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 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/arrow-counterclockwise.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/chat-square-quote.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/chevron-down.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/code.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/journal-code.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/journal-text.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/justify.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/link.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/list-ol.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/list-ul.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/pencil-fill.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/text-center.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/text-left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/text-paragraph.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/text-right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/type-bold.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/type-h1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/type-h2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/type-h3.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/type-italic.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/type-strikethrough.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Editor/images/icons/type-underline.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/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 ? : null}
24 | >
25 | )}
26 | >
27 | {children}
28 | {includeFooter ? : null}
29 |
30 | );
31 |
32 | export default ErrorBoundaryPage;
33 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Hero.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Hero: React.FC<{ image: string; children: React.ReactNode }> = ({ image, children, ...rest }) => {
4 | const style: React.CSSProperties = {
5 | display: 'flex',
6 | flexDirection: 'column',
7 | alignItems: 'center',
8 | justifyItems: 'center',
9 | color: '#fff',
10 | textAlign: 'center',
11 | backgroundImage: `url(${image})`,
12 | backgroundSize: 'cover',
13 | backgroundPositionY: 'center',
14 | padding: '128px 24px',
15 | margin: 0,
16 | marginBottom: 'var(--pf-v5-global--spacer--md)',
17 | };
18 | return (
19 |
20 | {children}
21 |
22 | );
23 | };
24 |
25 | export default Hero;
26 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/KeywordSearchInput.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { SearchInput } from '@patternfly/react-core';
3 |
4 | const KeywordSearchInput: React.FC<
5 | {
6 | initialValue?: string[];
7 | placeholder?: string;
8 | onSearch: (keywords: string[]) => void;
9 | } & React.HTMLAttributes
10 | > = ({ initialValue, placeholder, onSearch, ...rest }) => {
11 | const [value, setValue] = useState(initialValue ? initialValue.join(' ') : '');
12 |
13 | return (
14 | setValue(v)}
20 | onClear={() => {
21 | setValue('');
22 | onSearch(null);
23 | }}
24 | onSearch={() => {
25 | const trimmedValue = value.trim();
26 | if (trimmedValue === '') {
27 | onSearch(null);
28 | } else {
29 | onSearch(value.trim().split(/ +/));
30 | }
31 | }}
32 | />
33 | );
34 | };
35 |
36 | export default KeywordSearchInput;
37 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/Label.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Tooltip } from '@patternfly/react-core';
3 |
4 | const Label: React.FC<{ tooltipDescription?: JSX.Element; children: React.ReactNode }> = ({
5 | children,
6 | tooltipDescription = null,
7 | }) =>
8 | children && tooltipDescription ? (
9 |
10 |
22 | {children}
23 |
24 |
25 | ) : children ? (
26 |
37 | {children}
38 |
39 | ) : null;
40 |
41 | export default Label;
42 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/LoadingIcon.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import './loading-icon.css';
4 |
5 | const LoadingIcon: React.FC<{
6 | className?: string;
7 | }> = ({ className }) => (
8 |
13 | );
14 |
15 | export default LoadingIcon;
16 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/LoadingSection.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { EmptyState, EmptyStateIcon, PageSection, EmptyStateHeader } from '@patternfly/react-core';
3 | import LoadingIcon from './LoadingIcon';
4 |
5 | const LoadingSection: React.FC = () => (
6 |
7 |
8 | } />
9 |
10 |
11 | );
12 |
13 | export default LoadingSection;
14 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/LocalTimestamp.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { getLang } from '@app/util';
3 |
4 | const LocalTimestamp: React.FC<
5 | {
6 | date?: Date;
7 | time?: number;
8 | timestamp?: string;
9 | variant?: 'short' | 'long';
10 | includeTimezone?: boolean;
11 | } & React.HTMLAttributes
12 | > = ({ date, time, timestamp, variant = 'long', includeTimezone = true, ...props }) => {
13 | const ts = (date || new Date(time ? time : Date.parse(timestamp))).toLocaleDateString([getLang(), 'en-US'], {
14 | ...(variant === 'short' ? { year: '2-digit' } : { year: 'numeric' }),
15 | month: '2-digit',
16 | day: '2-digit',
17 | hour: '2-digit',
18 | minute: '2-digit',
19 | ...(includeTimezone ? { timeZoneName: 'short' } : {}),
20 | });
21 | return {ts};
22 | };
23 |
24 | export default LocalTimestamp;
25 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/NotFound.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { EmptyState, EmptyStateBody, EmptyStateIcon, EmptyStateHeader } from '@patternfly/react-core';
3 | import ExclamationTriangleIcon from '@patternfly/react-icons/dist/js/icons/exclamation-triangle-icon';
4 |
5 | const NotFoundComponent: React.FC<{
6 | name: string;
7 | namespace?: string;
8 | type: string;
9 | }> = ({ name, namespace, type }) => (
10 |
11 | {type} not found>}
13 | icon={}
14 | headingLevel="h1"
15 | />
16 |
17 | {type} {name} was not found{namespace ? ` in project ${namespace}` : ''}.
18 |
19 |
20 | );
21 |
22 | export default NotFoundComponent;
23 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/RefreshButton.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Button } from '@patternfly/react-core';
3 | import RedoIcon from '@patternfly/react-icons/dist/js/icons/redo-icon';
4 |
5 | const RefreshButton: React.FunctionComponent<{
6 | onClick: () => void;
7 | }> = ({ onClick }) => {
8 | return (
9 | } onClick={() => onClick()} variant="tertiary">
10 | Refresh
11 |
12 | );
13 | };
14 |
15 | export default RefreshButton;
16 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/ResourceClaimStopModal.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { ResourceClaim } from '@app/types';
3 | import { displayName } from '@app/util';
4 |
5 | const ResourceClaimStopModal: React.FC<{
6 | onConfirm: () => Promise;
7 | resourceClaims: ResourceClaim[];
8 | setTitle?: React.Dispatch>;
9 | setOnConfirmCb?: (_: any) => Promise;
10 | }> = ({ onConfirm, resourceClaims, setTitle, setOnConfirmCb }) => {
11 | useEffect(() => {
12 | setOnConfirmCb(() => onConfirm);
13 | }, [onConfirm, setOnConfirmCb]);
14 | useEffect(() => {
15 | setTitle(
16 | resourceClaims.length === 1 ? `Stop service ${displayName(resourceClaims[0])}?` : 'Stop selected services?',
17 | );
18 | }, [resourceClaims, setTitle]);
19 | return Cloud services will be stopped as supported by service deployer.
;
20 | };
21 |
22 | export default ResourceClaimStopModal;
23 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/SelectableTable.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Table, TableHeader, TableBody } from '@patternfly/react-table/deprecated';
3 |
4 | const SelectableTable: React.FC<{
5 | columns: any[];
6 | onSelectAll: any;
7 | rows: any[];
8 | }> = ({ columns, onSelectAll, rows }) => {
9 | function onSelect(_: any, isSelected: boolean, rowId: string | number) {
10 | if (rowId === -1) {
11 | onSelectAll(isSelected);
12 | } else {
13 | const rowOnSelect = rows[rowId]?.onSelect;
14 | if (rowOnSelect) {
15 | rowOnSelect(isSelected);
16 | }
17 | }
18 | }
19 |
20 | return (
21 |
25 | );
26 | };
27 |
28 | export default SelectableTable;
29 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/StatusPageIcons/DegradedPerformance.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | const DegradedPerformance = (props) => (
4 |
10 | );
11 |
12 | export default DegradedPerformance;
13 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/StatusPageIcons/MajorOutage.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | const MajorOutage = (props) => (
4 |
19 | );
20 |
21 | export default MajorOutage;
22 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/StatusPageIcons/Operational.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | const Operational = (props) => (
4 |
13 | );
14 |
15 | export default Operational;
16 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/StatusPageIcons/PartialOutage.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | const PartialOutage = (props) => (
4 |
14 | );
15 |
16 | export default PartialOutage;
17 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/StatusPageIcons/UnderMaintenance.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | const UnderMaintenance = (props) => (
4 |
11 | );
12 |
13 | export default UnderMaintenance;
14 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/StatusPageIcons/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Operational from './Operational';
3 | import PartialOutage from './PartialOutage';
4 | import MajorOutage from './MajorOutage';
5 | import DegradedPerformance from './DegradedPerformance';
6 | import UnderMaintenance from './UnderMaintenance';
7 |
8 | const StatusPageIcons: React.FC<{ status: string } & React.HTMLAttributes> = ({
9 | status,
10 | ...props
11 | }) => {
12 | switch (status) {
13 | case 'Degraded performance':
14 | return ;
15 | case 'Partial outage':
16 | return ;
17 | case 'Major outage':
18 | return ;
19 | case 'Under maintenance':
20 | return ;
21 | default:
22 | return ;
23 | }
24 | };
25 |
26 | export default StatusPageIcons;
27 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/TermsOfService.tsx:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from 'react';
2 | import { Checkbox, FormGroup } from '@patternfly/react-core';
3 | import { renderContent } from '@app/util';
4 |
5 | const TermsOfService: React.FC<{
6 | agreed: boolean;
7 | onChange: (event: React.FormEvent, checked: boolean) => void;
8 | text?: string;
9 | }> = ({ agreed, onChange, text }) => {
10 | const tosHtml = useMemo(
11 | () => ,
12 | [text],
13 | );
14 | return (
15 |
16 | {tosHtml}
17 |
23 |
24 | );
25 | };
26 |
27 | export default TermsOfService;
28 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/UnexpectedError.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { EmptyState, EmptyStateBody, EmptyStateIcon, EmptyStateHeader } from '@patternfly/react-core';
3 | import ExclamationTriangleIcon from '@patternfly/react-icons/dist/js/icons/exclamation-triangle-icon';
4 | import useHelpLink from '@app/utils/useHelpLink';
5 |
6 | const UnexpectedError: React.FC = () => {
7 | const helpLink = useHelpLink();
8 | return (
9 |
10 | }
13 | headingLevel="h1"
14 | />
15 |
16 | We track these errors automatically, but if the problem persists feel free to{' '}
17 |
18 | contact us
19 |
20 | .
21 |
22 |
23 | );
24 | };
25 | export default UnexpectedError;
26 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/WorkshopActionModal.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 |
3 | const WorkshopActionModal: React.FC<{
4 | onConfirm: () => Promise;
5 | action: 'start' | 'stop';
6 | setTitle?: React.Dispatch>;
7 | setOnConfirmCb?: (_: any) => Promise;
8 | }> = ({ onConfirm, action, setTitle, setOnConfirmCb }) => {
9 | useEffect(() => {
10 | setOnConfirmCb(() => onConfirm);
11 | }, [onConfirm, setOnConfirmCb]);
12 | useEffect(() => {
13 | setTitle(action === 'start' ? 'Start services?' : 'Stop services?');
14 | }, [setTitle, action]);
15 | return (
16 |
17 | {action === 'start'
18 | ? 'Cloud services will be started.'
19 | : 'Cloud services will be stopped as supported by service deployer.'}
20 |
21 | );
22 | };
23 |
24 | export default WorkshopActionModal;
25 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/action-dropdown.css:
--------------------------------------------------------------------------------
1 | .action-dropdown.pf-c-dropdown .pf-c-dropdown__toggle {
2 | font-size: 11pt;
3 | }
4 |
5 | .action-dropdown.pf-c-dropdown .pf-c-dropdown__menu-item {
6 | font-size: 11pt;
7 | padding-top: 4pt;
8 | padding-bottom: 4pt;
9 | }
10 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/bulk-user-assignment-modal.css:
--------------------------------------------------------------------------------
1 | .bulk-user-assignment-modal textarea.pf-v5-c-form-control {
2 | min-height: 8em;
3 | }
4 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/button-circle-icon.css:
--------------------------------------------------------------------------------
1 | .button-circle-icon {
2 | border-radius: 50%;
3 | border: 1px solid #d2d2d2;
4 | width: 36px;
5 | height: 36px;
6 | display: flex;
7 | flex-direction: column;
8 | align-items: center;
9 | justify-content: center;
10 | }
11 | .button-circle-icon.pf-m-disabled {
12 | opacity: 0.3;
13 | }
14 | .button-circle-icon svg {
15 | transition: fill 0.2s ease-in-out;
16 | }
17 | .button-circle-icon:hover svg {
18 | fill: var(--pf-v5-global--BackgroundColor--dark-100) !important;
19 | }
20 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/date-time-picker.css:
--------------------------------------------------------------------------------
1 | .date-time-picker__time-picker .pf-v5-c-dropdown__menu {
2 | overflow-y: auto;
3 | max-height: 380px;
4 | }
5 | .date-time-picker__text.pf-v5-c-form-control {
6 | font-size: var(--pf-v5-global--FontSize--sm);
7 | }
8 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/editable-text.css:
--------------------------------------------------------------------------------
1 | .editable-text-area.pf-v5-c-form-control {
2 | width: auto;
3 | }
4 |
5 | .editable-text-input.pf-v5-c-form-control {
6 | width: auto;
7 | }
8 |
9 | .editable-text-placeholder {
10 | color: var(--pf-v5-global--Color--400);
11 | }
12 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/footer.css:
--------------------------------------------------------------------------------
1 | .footer-component {
2 | background-color: #1a1a1a;
3 | margin-top: auto;
4 | }
5 | .footer__container {
6 | max-width: 1140px;
7 | width: 100%;
8 | display: flex;
9 | flex-direction: row;
10 | margin: 0 auto;
11 | padding: var(--pf-v5-global--spacer--md) var(--pf-v5-global--spacer--lg);
12 | }
13 | .footer__legal {
14 | flex: 1 0 60%;
15 | line-height: 2;
16 | align-items: center;
17 | justify-content: center;
18 | color: #aaa;
19 | font-size: 12px;
20 | display: flex;
21 | flex-direction: row;
22 | gap: var(--pf-v5-global--spacer--xl);
23 | }
24 | .footer__legal ul {
25 | display: flex;
26 | flex-direction: row;
27 | gap: var(--pf-v5-global--spacer--md);
28 | }
29 | .footer__legal a {
30 | text-decoration: underline;
31 | color: #aaa;
32 | }
33 | .footer__legal a:after {
34 | content: '|';
35 | display: inline-block;
36 | margin-left: var(--pf-v5-global--spacer--md);
37 | }
38 | .footer__legal li:last-child a:after,
39 | .footer__legal a > a:after {
40 | display: none;
41 | }
42 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/impersonate-user-modal.css:
--------------------------------------------------------------------------------
1 | .impersonate-user-modal.pf-m-sm.pf-v5-c-modal-box > .pf-v5-c-modal-box__body {
2 | overflow: visible;
3 | }
4 |
5 | .impersonate-user-modal.pf-m-sm.pf-v5-c-modal-box > .pf-v5-c-modal-box__body > .pf-c-context-selector {
6 | width: 100%;
7 | }
8 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/incidents-banner.css:
--------------------------------------------------------------------------------
1 | .pf-v5-c-banner.pf-m-gold {
2 | background-color: #fdf7e7;
3 | border-top: 2px solid #f0ab00;
4 | }
5 | .pf-v5-c-banner.pf-m-blue {
6 | background-color: #e7f1fa;
7 | border-top: 2px solid #2b9af3;
8 | }
9 | .pf-v5-c-banner.pf-m-blue a,
10 | .pf-v5-c-banner.pf-m-blue .editor-link {
11 | color: #151515 !important;
12 | }
13 | .pf-v5-c-banner.pf-m-red {
14 | background-color: #faeae8;
15 | color: #151515;
16 | border-top: 2px solid #c9190b;
17 | }
18 | .pf-v5-c-banner.pf-m-gold svg {
19 | fill: #f0ab00;
20 | }
21 | .pf-v5-c-banner.pf-m-blue svg {
22 | fill: #2b9af3;
23 | }
24 | .pf-v5-c-banner.pf-m-red svg {
25 | fill: #c9190b;
26 | }
27 | .incidents-banner__close-btn svg {
28 | fill: #6a6e73 !important;
29 | }
30 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/loading-icon.css:
--------------------------------------------------------------------------------
1 | .co-m-loader {
2 | min-width: 18px;
3 | }
4 |
5 | .co-m-loader-dot__one,
6 | .co-m-loader-dot__two,
7 | .co-m-loader-dot__three {
8 | animation-delay: 0;
9 | animation-direction: normal;
10 | animation-duration: 1s;
11 | animation-fill-mode: forwards;
12 | animation-iteration-count: infinite;
13 | animation-name: bouncedelay;
14 | animation-play-state: running;
15 | animation-timing-function: ease-in-out;
16 | background: #419eda;
17 | border-radius: 100%;
18 | display: inline-block;
19 | height: 6px;
20 | width: 6px;
21 | }
22 |
23 | .co-m-loader-dot__one {
24 | animation-delay: -0.32s;
25 | }
26 |
27 | .co-m-loader-dot__two {
28 | animation-delay: -0.16s;
29 | }
30 |
31 | @keyframes bouncedelay {
32 | 0%,
33 | 80%,
34 | 100% {
35 | transform: scale(0.25, 0.25);
36 | }
37 | 40% {
38 | transform: scale(1, 1);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/openshift-console-link.css:
--------------------------------------------------------------------------------
1 | a.openshift-console-link > img {
2 | height: 1.2em;
3 | padding-left: 0.5em;
4 | }
5 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/components/project-selector.css:
--------------------------------------------------------------------------------
1 | .project-selector .pf-c-context-selector__toggle.pf-m-plain .pf-c-context-selector__toggle-text {
2 | overflow: visible;
3 | }
4 | .project-selector .pf-c-context-selector__menu {
5 | width: 400px;
6 | overflow: hidden;
7 | }
8 | .project-selector__item {
9 | text-overflow: ellipsis;
10 | overflow: hidden;
11 | white-space: nowrap;
12 | display: block;
13 | }
14 | .project-selector__loading {
15 | display: flex;
16 | flex-grow: 1;
17 | justify-content: center;
18 | }
19 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/custom-media.css:
--------------------------------------------------------------------------------
1 | @custom-media --small-viewport (max-width: 768px);
2 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/reducers.ts:
--------------------------------------------------------------------------------
1 | import { K8sObject } from '@app/types';
2 |
3 | export interface SelectedUidsAction {
4 | type: string;
5 | items?: K8sObject[];
6 | uids?: string[];
7 | }
8 |
9 | export function selectedUidsReducer(state: string[], action: SelectedUidsAction): string[] {
10 | if (action.type === 'clear') {
11 | return [];
12 | }
13 | const itemUids = action.uids || action.items.map((item) => item.metadata.uid);
14 | switch (action.type) {
15 | case 'add':
16 | return [...state, ...itemUids.filter((uid) => !state.includes(uid))];
17 | case 'remove':
18 | return [...state.filter((uid) => !itemUids.includes(uid))];
19 | case 'set':
20 | return itemUids;
21 | default:
22 | throw new Error(`Invalid SelectedUidsAction type: ${action.type}`);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/utils/useDebounce.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef, useState } from 'react';
2 |
3 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
4 | function useDebounce(inner: (...args: any[]) => unknown, ms = 0): (...args: unknown[]) => Promise {
5 | const [timer, setTimer] = useState(null);
6 | const [resolves, setResolves] = useState([]);
7 | const callbackRef = useRef((...args: unknown[]) => {
8 | clearTimeout(timer);
9 | setTimer(
10 | setTimeout(() => {
11 | // Get the result of the inner function, then apply it to the resolve function of
12 | // each promise that has been created since the last time the inner function was run
13 | const result = inner(...args);
14 | resolves.forEach((r) => r(result));
15 | setResolves([]);
16 | }, ms),
17 | );
18 |
19 | return new Promise((r) => resolves.push(r));
20 | });
21 | useEffect(() => {
22 | return () => clearTimeout(timer);
23 | }, [timer]);
24 |
25 | return callbackRef.current;
26 | }
27 |
28 | export default useDebounce;
29 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/utils/useDocumentTitle.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react';
2 | import { useSearchParams } from 'react-router-dom';
3 |
4 | const DEFAULT_USER_INTERFACE = 'rhpds';
5 |
6 | function getPageTitle(title: string, userInterface?: string): string {
7 | if (!userInterface) userInterface = DEFAULT_USER_INTERFACE;
8 | return userInterface === 'summit'
9 | ? title.replace('Babylon', 'Red Hat Summit')
10 | : ['rhpds', 'rhdp', 'rhdp-partners'].includes(userInterface)
11 | ? title.replace('Babylon', 'Red Hat Demo Platform')
12 | : title;
13 | }
14 |
15 | // a custom hook for setting the page title
16 | function useDocumentTitle(title: string): void {
17 | const [searchParams] = useSearchParams();
18 | const userInterface = searchParams.get('userInterface');
19 | useEffect(() => {
20 | const originalTitle = document.title;
21 | if (title) document.title = getPageTitle(title, userInterface);
22 |
23 | return () => {
24 | document.title = originalTitle;
25 | };
26 | }, [title, userInterface]);
27 | }
28 |
29 | export default useDocumentTitle;
30 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/utils/useHelpLink.tsx:
--------------------------------------------------------------------------------
1 | import useImpersonateUser from './useImpersonateUser';
2 | import useInterfaceConfig from './useInterfaceConfig';
3 | import useSession from './useSession';
4 |
5 | export default function useHelpLink() {
6 | const { email } = useSession().getSession();
7 | const { userImpersonated } = useImpersonateUser();
8 | const { help_link, internal_help_link } = useInterfaceConfig();
9 | let userEmail = email;
10 | if (userImpersonated) {
11 | userEmail = userImpersonated;
12 | }
13 | if (userEmail.includes('@redhat.com')) {
14 | return internal_help_link;
15 | }
16 | return help_link;
17 | }
18 |
--------------------------------------------------------------------------------
/catalog/ui/src/app/utils/useRect.tsx:
--------------------------------------------------------------------------------
1 | import { RefObject, useCallback, useEffect, useRef, useState } from 'react';
2 | import throttle from 'lodash.throttle';
3 |
4 | const useEffectInEvent = (event: 'resize' | 'scroll', useCapture?: boolean, set?: () => void) => {
5 | useEffect(() => {
6 | set();
7 | window.addEventListener(event, set, useCapture);
8 | return () => window.removeEventListener(event, set, useCapture);
9 | }, []);
10 | };
11 |
12 | export const useRect = (): [DOMRect | undefined, RefObject] => {
13 | const ref = useRef(null);
14 | const [rect, setRect] = useState();
15 | const set = useCallback(
16 | throttle(() => setRect(ref.current?.getBoundingClientRect()), 1000),
17 | [setRect],
18 | );
19 |
20 | useEffectInEvent('resize', false, set);
21 | useEffectInEvent('scroll', true, set);
22 |
23 | return [rect, ref];
24 | };
25 |
--------------------------------------------------------------------------------
/catalog/ui/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redhat-cop/babylon/1305b9218a0d3da08c8586f194903434f1b9f13e/catalog/ui/src/favicon.ico
--------------------------------------------------------------------------------
/catalog/ui/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { StrictMode } from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import App from '@app/index';
4 | import { Provider } from 'react-redux';
5 | import { store } from './app/store';
6 |
7 | const container = document.getElementById('root');
8 | const root = createRoot(container);
9 | root.render(
10 |
11 |
12 |
13 |
14 | ,
15 | );
16 |
--------------------------------------------------------------------------------
/catalog/ui/src/public/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 | "sfdc_enabled": false,
12 | "partner_connect_header_enabled": true
13 | }
14 |
--------------------------------------------------------------------------------
/catalog/ui/src/public/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": "Get Technical Help",
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 | "workshop_support_text": "Workshop Support",
12 | "workshop_support_link": "https://redhat.service-now.com/help?id=sc_cat_item&sys_id=b48fe3cc870b2d508a51bbbf8bbb3576",
13 | "sfdc_enabled": true,
14 | "partner_connect_header_enabled": false
15 | }
16 |
--------------------------------------------------------------------------------
/catalog/ui/src/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.png';
2 | declare module '*.jpg';
3 | declare module '*.jpeg';
4 | declare module '*.gif';
5 | declare module '*.svg';
6 | declare module '*.css';
7 | declare module '*.wav';
8 | declare module '*.mp3';
9 | declare module '*.m4a';
10 | declare module '*.rdf';
11 | declare module '*.ttl';
12 | declare module '*.pdf';
13 |
--------------------------------------------------------------------------------
/catalog/ui/stylePaths.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | module.exports = {
3 | stylePaths: [
4 | path.resolve(__dirname, 'src'),
5 | path.resolve(__dirname, 'node_modules/@patternfly/react-styles/css'),
6 | path.resolve(__dirname, 'node_modules/@patternfly/react-core/dist/styles/base.css'),
7 | path.resolve(__dirname, 'node_modules/@patternfly/react-core/node_modules/@patternfly/react-styles/css'),
8 | path.resolve(__dirname, 'node_modules/@patternfly/react-table/node_modules/@patternfly/react-styles/css'),
9 | ],
10 | };
11 |
--------------------------------------------------------------------------------
/catalog/ui/test-setup.ts:
--------------------------------------------------------------------------------
1 | import '@testing-library/jest-dom';
2 | import fetchMock from 'jest-fetch-mock';
3 |
4 | fetchMock.enableMocks();
5 | jest.mock(
6 | 'asciidoctor',
7 | () => jest.fn(() => 'mocked'), // <= ...this mock function
8 | );
9 |
--------------------------------------------------------------------------------
/catalog/ui/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": true,
4 | "allowSyntheticDefaultImports": true,
5 | "baseUrl": ".",
6 | "downlevelIteration": true,
7 | "esModuleInterop": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "importHelpers": true,
10 | "jsx": "react",
11 | "lib": ["es2019", "dom", "dom.iterable"],
12 | "module": "esnext",
13 | "moduleResolution": "node",
14 | "noImplicitAny": false,
15 | "noImplicitReturns": true,
16 | "noImplicitThis": true,
17 | "outDir": "dist",
18 | "paths": {
19 | "@app/*": ["src/app/*"],
20 | "@assets/*": ["node_modules/@patternfly/react-core/dist/styles/assets/*"]
21 | },
22 | "rootDir": ".",
23 | "skipLibCheck": true,
24 | "sourceMap": true,
25 | "strictNullChecks": false,
26 | "strict": true,
27 | "target": "es5",
28 | "typeRoots": ["node_modules/@types"],
29 | "resolveJsonModule": true
30 | },
31 | "include": ["**/*.ts", "**/*.tsx", "**/*.jsx", "**/*.js", "./test-setup.ts"],
32 | "exclude": ["node_modules"]
33 | }
34 |
--------------------------------------------------------------------------------
/cost-tracker/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .odo/env
3 | .odo/odo-file-index.json
--------------------------------------------------------------------------------
/cost-tracker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM quay.io/redhat-cop/python-kopf-s2i:v1.35
2 |
3 | USER root
4 |
5 | COPY . /tmp/src
6 |
7 | RUN dnf install -y @ruby && \
8 | gem install asciidoctor && \
9 | rm -rf /tmp/src/.git* && \
10 | chown -R 1001 /tmp/src && \
11 | chgrp -R 0 /tmp/src && \
12 | chmod -R g+w /tmp/src
13 |
14 | USER 1001
15 |
16 | RUN /usr/libexec/s2i/assemble
17 |
18 | CMD ["/usr/libexec/s2i/run"]
19 |
--------------------------------------------------------------------------------
/cost-tracker/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 | dedicatedPod: false
23 | image: quay.io/redhat-cop/python-kopf-s2i
24 | mountSources: true
25 | sourceMapping: /tmp/projects
26 | name: s2i-builder
27 | metadata:
28 | name: babylon-cost-tracker
29 | version: 1.0.0
30 | schemaVersion: 2.0.0
31 |
--------------------------------------------------------------------------------
/cost-tracker/helm/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | name: babylon-cost-tracker
3 | description: A Helm chart for the babylon cost tracker component.
4 | type: application
5 | version: 0.1.0
6 | appVersion: 0.1.0
7 |
--------------------------------------------------------------------------------
/cost-tracker/helm/templates/aws-sandbox-manager-secret.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.awsSandboxManagerCredentials }}
2 | apiVersion: v1
3 | kind: Secret
4 | metadata:
5 | name: {{ include "babylon-cost-tracker.awsSandboxManagerSecretName" . }}
6 | namespace: {{ include "babylon-cost-tracker.namespaceName" . }}
7 | labels:
8 | {{- include "babylon-cost-tracker.labels" . | nindent 4 }}
9 | data:
10 | aws_access_key_id: {{ .Values.awsSandboxManagerCredentials.awsAccessKeyId | b64enc }}
11 | aws_secret_access_key: {{ .Values.awsSandboxManagerCredentials.awsSecretAccessKey | b64enc }}
12 | {{ end }}
13 |
--------------------------------------------------------------------------------
/cost-tracker/helm/templates/namespace.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.namespace.create }}
2 | apiVersion: v1
3 | kind: Namespace
4 | metadata:
5 | name: {{ include "babylon-cost-tracker.namespaceName" . }}
6 | {{ end }}
7 |
--------------------------------------------------------------------------------
/cost-tracker/helm/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.deploy }}
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: {{ include "babylon-cost-tracker.serviceAccountName" . }}
6 | namespace: {{ include "babylon-cost-tracker.namespaceName" . }}
7 | labels:
8 | {{- include "babylon-cost-tracker.labels" . | nindent 4 }}
9 | {{ end }}
10 |
--------------------------------------------------------------------------------
/cost-tracker/kopf-opt.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | KOPF_OPTIONS="--log-format=json"
3 | KOPF_PEERING="babylon-cost-tracker"
4 |
--------------------------------------------------------------------------------
/cost-tracker/operator/anarchy_subject.py:
--------------------------------------------------------------------------------
1 | class AnarchySubject:
2 | def __init__(self, definition):
3 | self.definition = definition
4 |
5 | @property
6 | def aws_sandbox_account(self):
7 | return self.job_vars.get('sandbox_account')
8 |
9 | @property
10 | def guid(self):
11 | return self.job_vars.get('guid')
12 |
13 | @property
14 | def job_vars(self):
15 | return self.vars.get('job_vars', {})
16 |
17 | @property
18 | def metadata(self):
19 | return self.definition['metadata']
20 |
21 | @property
22 | def name(self):
23 | return self.metadata['name']
24 |
25 | @property
26 | def namespace(self):
27 | return self.metadata['namespace']
28 |
29 | @property
30 | def spec(self):
31 | return self.definition['spec']
32 |
33 | @property
34 | def vars(self):
35 | return self.spec.get('vars', {})
36 |
--------------------------------------------------------------------------------
/cost-tracker/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 |
--------------------------------------------------------------------------------
/cost-tracker/requirements.txt:
--------------------------------------------------------------------------------
1 | boto3==1.24.19
2 | botocore==1.27.19
3 |
--------------------------------------------------------------------------------
/docs/Architecture_Poolboy.adoc:
--------------------------------------------------------------------------------
1 | == Poolboy
2 |
3 | Poolboy manages requests for infrastructure provisioning and pools of preallocated environments.
4 |
5 | image::images/BabylonArchitecture-Poolboy.png[width=95%,align="center"]
6 |
7 | Catalog requests are recorded as ResourceClaims in user namespaces.
8 |
9 | Each ResourceClaim includes one or more resource templates in its `spec` section.
10 |
11 | Each resource template in the ResourceClaim is matched to a ResourceProvider which sets defaults and validates values used in the template.
12 |
13 | The ResourceClaim is matched to an existing ResourceHandle or a new one is dynamically created based on the resource templates within the ResourceClaim.
14 |
15 | ResourceHandles may be preallocated from ResourcePools to allow for environments to be fully provisioned in advance of user requests.
16 |
17 | The ResourceProvider and resource templates in the ResourceHandle are combined to manage an AnarchySubject for each template. As the AnarchySubject changes its state is replicated into the status of the ResourceClaim to allow controlled access to the AnarchySubject data for the user.
18 |
--------------------------------------------------------------------------------
/docs/Deploying_Babylon.adoc:
--------------------------------------------------------------------------------
1 | == Deploying a complete Babylon Suite
2 |
3 | This document summarizes how to deploy the complete Babylon suite of components
4 |
5 | 1. Deploy Dark Tower per the link:Deploying_dark_tower.adoc[Deploying `dev|test|prod` Dark Tower clusters] doc.
6 | 2. Deploy OpenShift Container Platform cluster per the link:Deploying_OpenShift.adoc[Deploying OpenShift Container Platform] doc.
7 | 3. Deploy Operators and configure OCP per the link:Configuring_OpenShift.adoc[Configuring OpenShift].
8 | 4. Setup link:Metrics.adoc[Metrics].
9 |
10 |
11 | == Recommended setup
12 |
13 | - 4 ocp workers `m5.2xlarge`
14 | - 3 tower masters `c5.4xlarge`
15 | - 1 tower support (postgresql) `i4.4xlarge`
16 | - 5+ replicas of anarchy-runners
17 |
--------------------------------------------------------------------------------
/docs/README.adoc:
--------------------------------------------------------------------------------
1 | == Project Babylon documentation
2 |
3 | * Start with link:Deploying_Babylon.adoc[Deploying Babylon Suite of Components]
4 |
--------------------------------------------------------------------------------
/docs/images/BabylonArchitecture-Poolboy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redhat-cop/babylon/1305b9218a0d3da08c8586f194903434f1b9f13e/docs/images/BabylonArchitecture-Poolboy.png
--------------------------------------------------------------------------------
/docs/images/babylon-high-level.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redhat-cop/babylon/1305b9218a0d3da08c8586f194903434f1b9f13e/docs/images/babylon-high-level.png
--------------------------------------------------------------------------------
/helm/.helmignore:
--------------------------------------------------------------------------------
1 | .*.swo
2 | .*.swp
3 |
--------------------------------------------------------------------------------
/helm/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | name: babylon
3 | description: A Helm chart for babylon
4 | type: application
5 | version: 0.0.0
6 | appVersion: 0.0.0
7 |
--------------------------------------------------------------------------------
/helm/templates/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{/* vim: set filetype=mustache: */}}
2 | {{- define "babylon.name" -}}
3 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
4 | {{- end -}}
5 |
6 | {{- define "babylon.chart" -}}
7 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
8 | {{- end -}}
9 |
10 | {{- define "babylon.labels" -}}
11 | helm.sh/chart: {{ include "babylon.chart" . }}
12 | app.kubernetes.io/managed-by: {{ .Release.Service }}
13 | app.kubernetes.io/name: {{ include "babylon.name" . }}
14 | {{- if (ne (.Release.Name | upper) "RELEASE-NAME") }}
15 | app.kubernetes.io/instance: {{ .Release.Name }}
16 | {{- end -}}
17 | {{- if .Chart.AppVersion }}
18 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
19 | {{- end }}
20 | {{- end -}}
21 |
22 | {{- define "babylon.selectorLabels" -}}
23 | app.kubernetes.io/name: {{ include "babylon.name" . }}
24 | {{- if (ne (.Release.Name | upper) "RELEASE-NAME") }}
25 | app.kubernetes.io/instance: {{ .Release.Name }}
26 | {{- end -}}
27 | {{- end -}}
28 |
--------------------------------------------------------------------------------
/helm/templates/admin/namespace.yaml:
--------------------------------------------------------------------------------
1 | {{- if and .Values.admin.deploy .Values.admin.namespace.create }}
2 | ---
3 | apiVersion: v1
4 | kind: Namespace
5 | metadata:
6 | labels:
7 | {{- include "babylon.labels" $ | nindent 4 }}
8 | app.kubernetes.io/component: admin
9 | name: {{ .Values.admin.namespace.name }}
10 | {{- end }}
11 |
--------------------------------------------------------------------------------
/helm/templates/admin/service.yaml:
--------------------------------------------------------------------------------
1 | {{- $admin := .Values.admin }}
2 | {{- if $admin.deploy }}
3 | ---
4 | apiVersion: v1
5 | kind: Service
6 | metadata:
7 | labels:
8 | {{- include "babylon.labels" . | nindent 4 }}
9 | app.kubernetes.io/component: admin
10 | name: babylon-admin
11 | namespace: {{ $admin.namespace.name }}
12 | spec:
13 | type: ClusterIP
14 | ports:
15 | - name: admin-api
16 | port: 8080
17 | protocol: TCP
18 | targetPort: 8080
19 | selector:
20 | {{- include "babylon.selectorLabels" . | nindent 4 }}
21 | app.kubernetes.io/component: admin
22 | {{- end }}
23 |
--------------------------------------------------------------------------------
/helm/templates/admin/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{- $admin := .Values.admin }}
2 | {{- if and $admin.deploy }}
3 | ---
4 | apiVersion: v1
5 | kind: ServiceAccount
6 | metadata:
7 | name: babylon-admin
8 | namespace: {{ $admin.namespace.name }}
9 | labels:
10 | {{- include "babylon.labels" . | nindent 4 }}
11 | app.kubernetes.io/component: admin
12 | {{- end }}
--------------------------------------------------------------------------------
/helm/templates/admin/servicenow-secret.yaml:
--------------------------------------------------------------------------------
1 | {{- $admin := .Values.admin }}
2 | {{- if $admin.servicenow.deploy }}
3 | apiVersion: bitwarden-k8s-secrets-manager.demo.redhat.com/v1
4 | kind: BitwardenSyncSecret
5 | metadata:
6 | name: {{ $admin.servicenow.secretName | default "babylon-admin-servicenow" }}
7 | namespace: {{ $admin.namespace.name }}
8 | spec:
9 | data:
10 | authKey:
11 | secret: service_now
12 | key: auth_key
13 | workshopFormId:
14 | secret: service_now
15 | key: workshop_form_id
16 | {{- else }}
17 | ---
18 | apiVersion: v1
19 | kind: Secret
20 | metadata:
21 | name: {{ $admin.servicenow.secretName | default "babylon-admin-servicenow" }}
22 | namespace: {{ $admin.namespace.name }}
23 | labels:
24 | {{- include "babylon.labels" . | nindent 4 }}
25 | app.kubernetes.io/component: admin
26 | data:
27 | authKey: {{ required "$admin.servicenow.authKey is required!" $admin.servicenow.authKey | b64enc }}
28 | workshopFormId: {{ required "$admin.servicenow.workshopFormId is required!" $admin.servicenow.workshopFormId | b64enc }}
29 | {{- end }}
--------------------------------------------------------------------------------
/helm/templates/agnosticv/operator/clusterrole.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | {{- include "babylon.labels" $ | nindent 4 }}
7 | app.kubernetes.io/component: agnosticv-operator
8 | name: babylon-agnosticv-operator
9 | rules:
10 | - apiGroups:
11 | - {{ .Values.anarchy.api.group }}
12 | resources:
13 | - anarchygovernors
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - {{ .Values.catalog.api.group }}
24 | resources:
25 | - catalogitems
26 | verbs:
27 | - create
28 | - delete
29 | - get
30 | - list
31 | - patch
32 | - update
33 | - watch
34 | - apiGroups:
35 | - {{ .Values.resourceBroker.api.group }}
36 | resources:
37 | - resourceproviders
38 | verbs:
39 | - create
40 | - delete
41 | - get
42 | - list
43 | - patch
44 | - update
45 | - watch
46 | - apiGroups:
47 | - {{ .Values.resourceBroker.api.group }}
48 | resources:
49 | - resourceclaims
50 | verbs:
51 | - get
52 | - list
53 | - watch
54 |
--------------------------------------------------------------------------------
/helm/templates/agnosticv/operator/clusterrolebinding.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRoleBinding
4 | metadata:
5 | name: babylon-agnosticv-operator
6 | roleRef:
7 | apiGroup: rbac.authorization.k8s.io
8 | kind: ClusterRole
9 | name: babylon-agnosticv-operator
10 | subjects:
11 | - kind: ServiceAccount
12 | name: agnosticv-operator
13 | namespace: {{ .Values.configNamespace.name }}
14 |
--------------------------------------------------------------------------------
/helm/templates/agnosticv/operator/role.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: Role
4 | metadata:
5 | labels:
6 | {{- include "babylon.labels" $ | nindent 4 }}
7 | app.kubernetes.io/component: agnosticv-operator
8 | name: agnosticv-operator
9 | namespace: {{ $.Values.configNamespace.name }}
10 | rules:
11 | - apiGroups:
12 | - {{ .Values.agnosticv.api.group }}
13 | resources:
14 | - agnosticvrepos
15 | verbs:
16 | - get
17 | - list
18 | - patch
19 | - update
20 | - watch
21 | - apiGroups:
22 | - {{ .Values.agnosticv.api.group }}
23 | resources:
24 | - agnosticvrepos/status
25 | verbs:
26 | - create
27 | - patch
28 | - update
29 | - apiGroups:
30 | - {{ .Values.agnosticv.api.group }}
31 | resources:
32 | - agnosticvcomponents
33 | - agnosticvcomponents/status
34 | verbs:
35 | - create
36 | - delete
37 | - get
38 | - list
39 | - patch
40 | - update
41 | - watch
42 | - apiGroups:
43 | - ''
44 | resources:
45 | - secrets
46 | verbs:
47 | - get
48 | - apiGroups:
49 | - ""
50 | resources:
51 | - events
52 | verbs:
53 | - create
54 | - patch
55 | - update
56 |
--------------------------------------------------------------------------------
/helm/templates/agnosticv/operator/rolebinding.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: RoleBinding
4 | metadata:
5 | name: agnosticv-operator
6 | namespace: {{ .Values.configNamespace.name }}
7 | labels:
8 | {{- include "babylon.labels" $ | nindent 4 }}
9 | app.kubernetes.io/component: agnosticv-operator
10 | roleRef:
11 | apiGroup: rbac.authorization.k8s.io
12 | kind: Role
13 | name: agnosticv-operator
14 | subjects:
15 | - kind: ServiceAccount
16 | name: agnosticv-operator
17 | namespace: {{ .Values.configNamespace.name }}
18 |
--------------------------------------------------------------------------------
/helm/templates/agnosticv/operator/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: agnosticv-operator
6 | namespace: {{ .Values.configNamespace.name }}
7 | labels:
8 | {{- include "babylon.labels" $ | nindent 4 }}
9 | app.kubernetes.io/component: agnosticv-operator
10 |
--------------------------------------------------------------------------------
/helm/templates/anarchy/communes.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.anarchy.configureCommunes }}
2 | {{- range $namespace := .Values.anarchy.namespaces }}
3 | ---
4 | apiVersion: {{ $.Values.anarchy.api.group }}/{{ $.Values.anarchy.api.version }}
5 | kind: AnarchyCommune
6 | metadata:
7 | name: anarchy
8 | namespace: {{ $namespace.name }}
9 | labels:
10 | {{- include "babylon.labels" $ | nindent 4 }}
11 | app.kubernetes.io/component: anarchy
12 | spec:
13 | runners:
14 | default:
15 | {{- (get $.Values.anarchy.namespaceProfiles ($namespace.profile | default "default")) | toYaml | nindent 6 }}
16 | {{- end }}
17 | {{- end }}
18 |
--------------------------------------------------------------------------------
/helm/templates/anarchy/namespaces.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace := .Values.anarchy.namespaces }}
2 | ---
3 | apiVersion: v1
4 | kind: Namespace
5 | metadata:
6 | labels:
7 | {{- include "babylon.labels" $ | nindent 4 }}
8 | app.kubernetes.io/component: anarchy
9 | name: {{ $namespace.name }}
10 | {{- end }}
11 |
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/api/clusterrole.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | {{- include "babylon.labels" $ | nindent 4 }}
7 | app.kubernetes.io/component: catalog-api
8 | name: babylon-catalog-api
9 | rules:
10 | - apiGroups:
11 | - ""
12 | - user.openshift.io
13 | resources:
14 | - groups
15 | - users
16 | verbs:
17 | - get
18 | - impersonate
19 | - list
20 | - apiGroups:
21 | - ""
22 | resources:
23 | - namespaces
24 | - secrets
25 | verbs:
26 | - get
27 | - list
28 | - apiGroups:
29 | - babylon.gpte.redhat.com
30 | resources:
31 | - workshops
32 | - workshopuserassignments
33 | verbs:
34 | - get
35 | - list
36 | - patch
37 | - watch
38 | - update
39 |
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/api/clusterrolebinding.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace, $interface := .Values.catalog.interfaces }}
2 | ---
3 | apiVersion: rbac.authorization.k8s.io/v1
4 | kind: ClusterRoleBinding
5 | metadata:
6 | name: babylon-catalog-api:{{ $namespace }}
7 | labels:
8 | {{- include "babylon.labels" $ | nindent 4 }}
9 | app.kubernetes.io/component: catalog-api
10 | roleRef:
11 | apiGroup: rbac.authorization.k8s.io
12 | kind: ClusterRole
13 | name: babylon-catalog-api
14 | subjects:
15 | - kind: ServiceAccount
16 | name: babylon-catalog-api
17 | namespace: {{ $namespace }}
18 | {{- end }}
19 |
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/api/salesforce-api-secret.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace, $interface := .Values.catalog.interfaces }}
2 | ---
3 | apiVersion: bitwarden-k8s-secrets-manager.demo.redhat.com/v1
4 | kind: BitwardenSyncSecret
5 | metadata:
6 | name: salesforce-api
7 | namespace: {{ $namespace }}
8 | spec:
9 | data:
10 | salesforce-api-token:
11 | secret: salesforce_api_login_token
12 | key: service_token
13 | {{- end }}
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/api/service.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace, $interface := .Values.catalog.interfaces }}
2 | ---
3 | apiVersion: v1
4 | kind: Service
5 | metadata:
6 | name: babylon-catalog-api
7 | namespace: {{ $namespace }}
8 | labels:
9 | {{- include "babylon.labels" $ | nindent 4 }}
10 | app.kubernetes.io/component: catalog-api
11 | spec:
12 | ports:
13 | - name: api
14 | port: 8080
15 | protocol: TCP
16 | targetPort: 8080
17 | selector:
18 | {{- include "babylon.selectorLabels" $ | nindent 4 }}
19 | app.kubernetes.io/component: catalog-api
20 | type: ClusterIP
21 | {{- end }}
22 |
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/api/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace, $interface := .Values.catalog.interfaces }}
2 | ---
3 | apiVersion: v1
4 | kind: ServiceAccount
5 | metadata:
6 | labels:
7 | {{- include "babylon.labels" $ | nindent 4 }}
8 | app.kubernetes.io/component: catalog-api
9 | name: babylon-catalog-api
10 | namespace: {{ $namespace }}
11 | {{- end }}
12 |
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/namespaces.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace, $_ := .Values.catalog.interfaces }}
2 | ---
3 | apiVersion: v1
4 | kind: Namespace
5 | metadata:
6 | labels:
7 | {{- include "babylon.labels" $ | nindent 4 }}
8 | app.kubernetes.io/component: catalog
9 | name: {{ $namespace }}
10 | {{- end }}
11 |
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/oauth-proxy/certificate.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace, $_interface := .Values.catalog.interfaces }}
2 | {{- $interface := merge $_interface (deepCopy $.Values.catalog.defaults) }}
3 | {{- $domain := $interface.route.host | default (printf "%s.%s" $namespace $.Values.ingressDomain) }}
4 | {{- if $interface.route.certManager.enable }}
5 | ---
6 | apiVersion: cert-manager.io/v1
7 | kind: Certificate
8 | metadata:
9 | labels:
10 | {{- include "babylon.labels" $ | nindent 4 }}
11 | app.kubernetes.io/component: oauth-proxy
12 | name: babylon-catalog
13 | namespace: {{ $namespace }}
14 | spec:
15 | dnsNames:
16 | - {{ $domain }}
17 | duration: 2160h0m0s # 90d
18 | issuerRef:
19 | name: letsencrypt
20 | kind: ClusterIssuer
21 | group: cert-manager.io
22 | privateKey:
23 | algorithm: RSA
24 | encoding: PKCS1
25 | size: 4096
26 | renewBefore: 360h0m0s # 15d
27 | secretName: babylon-catalog-tls
28 | usages:
29 | - server auth
30 | {{- end }}
31 | {{- end }}
32 |
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/oauth-proxy/oauth-proxy-cookie-secret.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace, $_interface := .Values.catalog.interfaces }}
2 | ---
3 | apiVersion: secretgenerator.mittwald.de/v1alpha1
4 | kind: StringSecret
5 | metadata:
6 | name: babylon-catalog-oauth-proxy-cookie
7 | namespace: {{ $namespace }}
8 | spec:
9 | forceRegenerate: false
10 | fields:
11 | - fieldName: cookieSecret
12 | encoding: base64
13 | length: "32"
14 | {{- end }}
15 |
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/oauth-proxy/oauthclientconfig.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace, $_interface := .Values.catalog.interfaces }}
2 | {{- $interface := merge $_interface (deepCopy $.Values.catalog.defaults) }}
3 | {{- $domain := $interface.route.host | default (printf "%s.%s" $namespace $.Values.ingressDomain) }}
4 | ---
5 | apiVersion: secretgenerator.mittwald.de/v1alpha1
6 | kind: StringSecret
7 | metadata:
8 | name: babylon-catalog-oauth-proxy-client
9 | namespace: {{ $namespace }}
10 | spec:
11 | forceRegenerate: false
12 | fields:
13 | - fieldName: clientSecret
14 | encoding: base64
15 | length: "32"
16 | ---
17 | apiVersion: rhpds.redhat.com/v1
18 | kind: OAuthClientConfig
19 | metadata:
20 | name: {{ $namespace }}
21 | spec:
22 | grantMethod: auto
23 | redirectURIs:
24 | - https://{{ $domain }}/oauth/callback
25 | secret:
26 | name: babylon-catalog-oauth-proxy-client
27 | namespace: {{ $namespace }}
28 | {{- end }}
29 |
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/oauth-proxy/service.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace, $_interface := .Values.catalog.interfaces }}
2 | ---
3 | apiVersion: v1
4 | kind: Service
5 | metadata:
6 | annotations:
7 | service.alpha.openshift.io/serving-cert-secret-name: babylon-catalog-oauth-proxy-tls
8 | labels:
9 | {{- include "babylon.labels" $ | nindent 4 }}
10 | app.kubernetes.io/component: oauth-proxy
11 | name: babylon-catalog-oauth-proxy
12 | namespace: {{ $namespace }}
13 | spec:
14 | ports:
15 | - name: proxy
16 | port: 443
17 | protocol: TCP
18 | targetPort: 8443
19 | selector:
20 | {{- include "babylon.selectorLabels" $ | nindent 4 }}
21 | app.kubernetes.io/component: oauth-proxy
22 | sessionAffinity: None
23 | type: ClusterIP
24 | {{- end }}
25 |
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/oauth-proxy/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace, $interface := .Values.catalog.interfaces }}
2 | ---
3 | apiVersion: v1
4 | kind: ServiceAccount
5 | metadata:
6 | annotations:
7 | serviceaccounts.openshift.io/oauth-redirectreference.primary: >-
8 | {"kind":"OAuthRedirectReference","apiVersion":"v1","reference":{"kind":"Route","name":"babylon-catalog"}}
9 | labels:
10 | {{- include "babylon.labels" $ | nindent 4 }}
11 | app.kubernetes.io/component: oauth-proxy
12 | name: babylon-catalog-oauth-proxy
13 | namespace: {{ $namespace }}
14 | {{- end }}
15 |
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/oauth-proxy/templates-configmap.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace, $_interface := .Values.catalog.interfaces }}
2 | {{- $interface := merge $_interface (deepCopy $.Values.catalog.defaults) }}
3 | {{- $oauthProxy := $interface.oauthProxy }}
4 | {{- with $oauthProxy.templates }}
5 | ---
6 | apiVersion: v1
7 | kind: ConfigMap
8 | metadata:
9 | labels:
10 | {{- include "babylon.labels" $ | nindent 4 }}
11 | app.kubernetes.io/component: oauth-proxy
12 | name: babylon-oauth-proxy-templates
13 | namespace: {{ $namespace }}
14 | data:
15 | {{- . | toYaml | nindent 2 }}
16 | {{- end }}
17 | {{- end }}
18 |
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/redis/secret.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace, $_interface := .Values.catalog.interfaces }}
2 | ---
3 | apiVersion: secretgenerator.mittwald.de/v1alpha1
4 | kind: StringSecret
5 | metadata:
6 | name: babylon-catalog-redis
7 | namespace: {{ $namespace }}
8 | spec:
9 | forceRegenerate: false
10 | fields:
11 | - fieldName: database-password
12 | encoding: base64
13 | length: "32"
14 | {{- end }}
15 |
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/redis/service.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace, $_ := .Values.catalog.interfaces }}
2 | ---
3 | apiVersion: v1
4 | kind: Service
5 | metadata:
6 | name: babylon-catalog-redis
7 | namespace: {{ $namespace }}
8 | labels:
9 | {{- include "babylon.labels" $ | nindent 4 }}
10 | app.kubernetes.io/component: catalog-redis
11 | spec:
12 | type: ClusterIP
13 | ports:
14 | - name: redis
15 | port: 6379
16 | protocol: TCP
17 | targetPort: 6379
18 | selector:
19 | {{- include "babylon.selectorLabels" $ | nindent 4 }}
20 | app.kubernetes.io/component: catalog-redis
21 | {{- end }}
22 |
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/status/service.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace, $interface := .Values.catalog.interfaces }}
2 | ---
3 | apiVersion: v1
4 | kind: Service
5 | metadata:
6 | name: babylon-catalog-status
7 | namespace: {{ $namespace }}
8 | labels:
9 | {{- include "babylon.labels" $ | nindent 4 }}
10 | app.kubernetes.io/component: status
11 | spec:
12 | ports:
13 | - name: proxy
14 | port: 8080
15 | protocol: TCP
16 | targetPort: 8080
17 | selector:
18 | {{- include "babylon.selectorLabels" $ | nindent 4 }}
19 | app.kubernetes.io/component: status
20 | type: ClusterIP
21 | {{- end }}
--------------------------------------------------------------------------------
/helm/templates/catalog/interfaces/ui/service.yaml:
--------------------------------------------------------------------------------
1 | {{- range $namespace, $interface := .Values.catalog.interfaces }}
2 | ---
3 | apiVersion: v1
4 | kind: Service
5 | metadata:
6 | name: babylon-catalog-ui
7 | namespace: {{ $namespace }}
8 | labels:
9 | {{- include "babylon.labels" $ | nindent 4 }}
10 | app.kubernetes.io/component: catalog-ui
11 | spec:
12 | ports:
13 | - name: api
14 | port: 8080
15 | protocol: TCP
16 | targetPort: 8080
17 | selector:
18 | {{- include "babylon.selectorLabels" $ | nindent 4 }}
19 | app.kubernetes.io/component: catalog-ui
20 | type: ClusterIP
21 | {{- end }}
22 |
--------------------------------------------------------------------------------
/helm/templates/clusterroles/babylon-cluster-reader.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | name: babylon-cluster-reader
6 | annotations:
7 | description: >-
8 | Cluster-wide read access for Babylon resources.
9 | labels:
10 | rbac.authorization.k8s.io/aggregate-to-cluster-reader: "true"
11 | {{- include "babylon.labels" . | nindent 4 }}
12 | rules:
13 | - apiGroups:
14 | - {{ .Values.catalog.api.group }}
15 | resources:
16 | - catalogitems
17 | verbs:
18 | - get
19 | - list
20 | - watch
21 | - apiGroups:
22 | - {{ .Values.anarchy.api.group }}
23 | resources:
24 | - anarchyactions
25 | - anarchycommunes
26 | - anarchygovernors
27 | - anarchyruns
28 | - anarchyrunners
29 | - anarchysubjects
30 | verbs:
31 | - get
32 | - list
33 | - watch
34 |
--------------------------------------------------------------------------------
/helm/templates/clusterroles/babylon-user-catalog-access.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | name: babylon-user-catalog-access
6 | annotations:
7 | description: >-
8 | Access to Babylon catalog resources.
9 | labels:
10 | rbac.authorization.k8s.io/aggregate-to-view: "true"
11 | {{- include "babylon.labels" . | nindent 4 }}
12 | rules:
13 | - apiGroups:
14 | - {{ .Values.catalog.api.group }}
15 | resources:
16 | - catalogitems
17 | verbs:
18 | - get
19 | - list
20 | - watch
21 | - apiGroups:
22 | - template.openshift.io
23 | resources:
24 | - templates
25 | verbs:
26 | - get
27 | - list
28 | - watch
29 |
--------------------------------------------------------------------------------
/helm/templates/clusterroles/babylon-user-service-access.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | name: babylon-user-service-access
6 | annotations:
7 | description: >-
8 | Access to manage Babylon services.
9 | labels:
10 | rbac.authorization.k8s.io/aggregate-to-edit: "true"
11 | {{- include "babylon.labels" . | nindent 4 }}
12 | rules:
13 | - apiGroups:
14 | - {{ .Values.resourceBroker.api.group }}
15 | resources:
16 | - resourceclaims
17 | verbs:
18 | - create
19 | - delete
20 | - deletecollection
21 | - get
22 | - list
23 | - patch
24 | - update
25 | - watch
26 | - apiGroups:
27 | - {{ .Values.catalog.api.group }}
28 | resources:
29 | - workshops
30 | - workshopprovisions
31 | - workshopuserassignments
32 | verbs:
33 | - create
34 | - delete
35 | - get
36 | - list
37 | - patch
38 | - watch
39 | - update
40 |
--------------------------------------------------------------------------------
/helm/templates/clusterroles/babylon-workshop-admin.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | name: babylon-workshop-admin
6 | annotations:
7 | description: >-
8 | Access to manage workshops and provisions for workshops.
9 | labels:
10 | rbac.authorization.k8s.io/aggregate-to-admin: "true"
11 | {{- include "babylon.labels" . | nindent 4 }}
12 | rules:
13 | - apiGroups:
14 | - {{ .Values.catalog.api.group }}
15 | resources:
16 | - workshops
17 | - workshopprovisions
18 | - workshopuserassignments
19 | verbs:
20 | - create
21 | - delete
22 | - get
23 | - list
24 | - patch
25 | - watch
26 | - update
27 |
--------------------------------------------------------------------------------
/helm/templates/clusterroles/catalog-access.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | name: babylon:anarchy:catalog-access
6 | annotations:
7 | description: >-
8 | This cluster role is used to allow anarchy to access catalog items and secrets.
9 | labels:
10 | {{- include "babylon.labels" . | nindent 4 }}
11 | rules:
12 | - apiGroups:
13 | - {{ .Values.catalog.api.group }}
14 | resources:
15 | - catalogitems
16 | verbs:
17 | - get
18 | - list
19 | - watch
20 | - apiGroups:
21 | - template.openshift.io
22 | resources:
23 | - templates
24 | verbs:
25 | - get
26 | - list
27 | - watch
28 | - apiGroups:
29 | - ""
30 | resources:
31 | - secrets
32 | verbs:
33 | - get
34 | - list
35 | - watch
36 |
--------------------------------------------------------------------------------
/helm/templates/config/namespace.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Namespace
4 | metadata:
5 | name: {{ .Values.configNamespace.name }}
6 | labels:
7 | {{- include "babylon.labels" . | nindent 4 }}
8 |
--------------------------------------------------------------------------------
/helm/templates/notifier/clusterrolebinding.yaml:
--------------------------------------------------------------------------------
1 | {{- $notifier := .Values.notifier }}
2 | {{- if and $notifier.deploy }}
3 | ---
4 | apiVersion: rbac.authorization.k8s.io/v1
5 | kind: ClusterRoleBinding
6 | metadata:
7 | name: babylon-notifier
8 | labels:
9 | {{- include "babylon.labels" . | nindent 4 }}
10 | app.kubernetes.io/component: notifier
11 | roleRef:
12 | apiGroup: rbac.authorization.k8s.io
13 | kind: ClusterRole
14 | name: babylon-notifier
15 | subjects:
16 | - kind: ServiceAccount
17 | name: babylon-notifier
18 | namespace: {{ $notifier.namespace.name }}
19 | {{- end }}
20 |
--------------------------------------------------------------------------------
/helm/templates/notifier/namespace.yaml:
--------------------------------------------------------------------------------
1 | {{- if and .Values.notifier.deploy .Values.notifier.namespace.create }}
2 | ---
3 | apiVersion: v1
4 | kind: Namespace
5 | metadata:
6 | labels:
7 | {{- include "babylon.labels" $ | nindent 4 }}
8 | app.kubernetes.io/component: notifier
9 | name: {{ .Values.notifier.namespace.name }}
10 | {{- end }}
11 |
--------------------------------------------------------------------------------
/helm/templates/notifier/redis/persistentvolumeclaim.yaml:
--------------------------------------------------------------------------------
1 | {{- $notifier := .Values.notifier }}
2 | {{- if $notifier.deploy }}
3 | {{- $redis := $notifier.redis }}
4 | ---
5 | apiVersion: v1
6 | kind: PersistentVolumeClaim
7 | metadata:
8 | labels:
9 | {{- include "babylon.labels" . | nindent 4 }}
10 | app.kubernetes.io/component: notifier-redis
11 | name: {{ $redis.persistentVolumeClaim.name | default "babylon-notifier-redis" }}
12 | namespace: {{ $notifier.namespace.name }}
13 | spec:
14 | {{- $redis.persistentVolumeClaim.spec | toYaml | nindent 2 }}
15 | {{- end }}
16 |
--------------------------------------------------------------------------------
/helm/templates/notifier/redis/secret.yaml:
--------------------------------------------------------------------------------
1 | {{- $notifier := .Values.notifier }}
2 | {{- if $notifier.deploy }}
3 | ---
4 | apiVersion: secretgenerator.mittwald.de/v1alpha1
5 | kind: StringSecret
6 | metadata:
7 | name: babylon-notifier-redis
8 | namespace: {{ $notifier.namespace.name }}
9 | spec:
10 | forceRegenerate: false
11 | fields:
12 | - fieldName: database-password
13 | encoding: base64
14 | length: "32"
15 | {{- end }}
16 |
--------------------------------------------------------------------------------
/helm/templates/notifier/redis/service.yaml:
--------------------------------------------------------------------------------
1 | {{- $notifier := .Values.notifier }}
2 | {{- if $notifier.deploy }}
3 | {{- $redis := $notifier.redis }}
4 | ---
5 | apiVersion: v1
6 | kind: Service
7 | metadata:
8 | labels:
9 | {{- include "babylon.labels" . | nindent 4 }}
10 | app.kubernetes.io/component: notifier-redis
11 | name: babylon-notifier-redis
12 | namespace: {{ $notifier.namespace.name }}
13 | spec:
14 | type: ClusterIP
15 | ports:
16 | - name: redis
17 | port: 6379
18 | protocol: TCP
19 | targetPort: 6379
20 | selector:
21 | {{- include "babylon.selectorLabels" . | nindent 4 }}
22 | app.kubernetes.io/component: notifier-redis
23 | {{- end }}
24 |
--------------------------------------------------------------------------------
/helm/templates/notifier/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{- $notifier := .Values.notifier }}
2 | {{- if and $notifier.deploy }}
3 | ---
4 | apiVersion: v1
5 | kind: ServiceAccount
6 | metadata:
7 | name: babylon-notifier
8 | namespace: {{ $notifier.namespace.name }}
9 | labels:
10 | {{- include "babylon.labels" . | nindent 4 }}
11 | app.kubernetes.io/component: notifier
12 | {{- end }}
13 |
--------------------------------------------------------------------------------
/helm/templates/notifier/smtp-secret.yaml:
--------------------------------------------------------------------------------
1 | {{- $notifier := .Values.notifier }}
2 | {{- if (and $notifier.deploy (eq ($notifier.smtp).host "smtp.sendgrid.net")) }}
3 | apiVersion: bitwarden-k8s-secrets-manager.demo.redhat.com/v1
4 | kind: BitwardenSyncSecret
5 | metadata:
6 | name: {{ ($notifier.smtp.auth).secretName | default "babylon-notifier-smtp-credentials" }}
7 | namespace: {{ $notifier.namespace.name }}
8 | spec:
9 | data:
10 | user:
11 | value: apikey
12 | password:
13 | secret: sendgrid_apikey
14 | {{- else if (and $notifier.deploy (($notifier.smtp).auth).user (($notifier.smtp).auth).password) }}
15 | ---
16 | apiVersion: v1
17 | kind: Secret
18 | metadata:
19 | name: {{ ($notifier.smtp.auth).secretName | default "babylon-notifier-smtp-credentials" }}
20 | namespace: {{ $notifier.namespace.name }}
21 | labels:
22 | {{- include "babylon.labels" . | nindent 4 }}
23 | app.kubernetes.io/component: notifier
24 | data:
25 | user: {{ $notifier.smtp.auth.user | b64enc }}
26 | password: {{ $notifier.smtp.auth.password | b64enc }}
27 | {{- end }}
28 |
--------------------------------------------------------------------------------
/helm/templates/resourceBroker/clusterrole.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | name: babylon:{{ .Values.resourceBroker.serviceAccountName }}:anarchy-access
6 | annotations:
7 | description: >-
8 | This role is used to allow the resource broker to manage anarchy resources.
9 | labels:
10 | {{- include "babylon.labels" . | nindent 4 }}
11 | rules:
12 | # ConfigMap access to create user configmaps
13 | - apiGroups:
14 | - ""
15 | resources:
16 | - configmaps
17 | verbs:
18 | - create
19 | - delete
20 | - get
21 | - list
22 | - patch
23 | - watch
24 | - update
25 | - apiGroups:
26 | - {{ .Values.anarchy.api.group }}
27 | resources:
28 | - anarchysubjects
29 | verbs:
30 | - create
31 | - delete
32 | - get
33 | - list
34 | - patch
35 | - watch
36 | - update
37 |
--------------------------------------------------------------------------------
/helm/templates/resourceBroker/clusterrolebinding.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRoleBinding
4 | metadata:
5 | name: babylon:{{ .Values.resourceBroker.namespace }}:anarchy-access
6 | annotations:
7 | description: >-
8 | This rolebinding allows the resource broker to manage anarchy resources.
9 | labels:
10 | {{- include "babylon.labels" . | nindent 4 }}
11 | roleRef:
12 | apiGroup: rbac.authorization.k8s.io
13 | kind: ClusterRole
14 | name: babylon:{{ .Values.resourceBroker.serviceAccountName }}:anarchy-access
15 | subjects:
16 | - kind: ServiceAccount
17 | name: {{ .Values.resourceBroker.serviceAccountName }}
18 | namespace: {{ .Values.resourceBroker.namespace }}
19 |
--------------------------------------------------------------------------------
/helm/templates/workshopManager/clusterrolebinding.yaml:
--------------------------------------------------------------------------------
1 | {{- $workshopManager := .Values.workshopManager }}
2 | {{- if and $workshopManager.deploy }}
3 | ---
4 | apiVersion: rbac.authorization.k8s.io/v1
5 | kind: ClusterRoleBinding
6 | metadata:
7 | name: babylon-workshop-manager
8 | labels:
9 | {{- include "babylon.labels" . | nindent 4 }}
10 | app.kubernetes.io/component: workshop-manager
11 | roleRef:
12 | apiGroup: rbac.authorization.k8s.io
13 | kind: ClusterRole
14 | name: babylon-workshop-manager
15 | subjects:
16 | - kind: ServiceAccount
17 | name: babylon-workshop-manager
18 | namespace: {{ $workshopManager.namespace.name }}
19 | {{- end }}
20 |
--------------------------------------------------------------------------------
/helm/templates/workshopManager/namespace.yaml:
--------------------------------------------------------------------------------
1 | {{- $workshopManager := .Values.workshopManager }}
2 | {{- if and $workshopManager.deploy $workshopManager.namespace.create }}
3 | ---
4 | apiVersion: v1
5 | kind: Namespace
6 | metadata:
7 | labels:
8 | {{- include "babylon.labels" $ | nindent 4 }}
9 | app.kubernetes.io/component: workshop-manager
10 | name: {{ $workshopManager.namespace.name }}
11 | {{- end }}
12 |
--------------------------------------------------------------------------------
/helm/templates/workshopManager/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{- $workshopManager := .Values.workshopManager }}
2 | {{- if and $workshopManager.deploy }}
3 | ---
4 | apiVersion: v1
5 | kind: ServiceAccount
6 | metadata:
7 | name: babylon-workshop-manager
8 | namespace: {{ $workshopManager.namespace.name }}
9 | labels:
10 | {{- include "babylon.labels" . | nindent 4 }}
11 | app.kubernetes.io/component: workshop-manager
12 | {{- end }}
13 |
--------------------------------------------------------------------------------
/lab-ui-manager/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .odo/env
3 | .odo/odo-file-index.json
--------------------------------------------------------------------------------
/lab-ui-manager/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM quay.io/redhat-cop/python-kopf-s2i:v1.35
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 |
--------------------------------------------------------------------------------
/lab-ui-manager/README.adoc:
--------------------------------------------------------------------------------
1 | = Bookbag Deployer
2 |
3 | Component to deploy Bookbag lab user interfaces for services that request it in the ResourceClaim.
4 |
--------------------------------------------------------------------------------
/lab-ui-manager/helm/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | name: babylon-lab-ui-manager
3 | description: A Helm chart for the babylon lab ui manager component.
4 |
5 | # A chart can be either an 'application' or a 'library' chart.
6 | #
7 | # Application charts are a collection of templates that can be packaged into versioned archives
8 | # to be deployed.
9 | #
10 | # Library charts provide useful utilities or functions for the chart developer. They're included as
11 | # a dependency of application charts to inject those utilities and functions into the rendering
12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed.
13 | type: application
14 |
15 | # This is the chart version. This version number should be incremented each time you make changes
16 | # to the chart and its templates, including the app version.
17 | version: 0.1.3
18 |
19 | # This is the version number of the application being deployed. This version number should be
20 | # incremented each time you make changes to the application.
21 | appVersion: 0.1.3
22 |
--------------------------------------------------------------------------------
/lab-ui-manager/helm/templates/namespace.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.namespace.create }}
2 | apiVersion: v1
3 | kind: Namespace
4 | metadata:
5 | name: {{ include "babylon-lab-ui-manager.namespaceName" . }}
6 | {{ end }}
7 |
--------------------------------------------------------------------------------
/lab-ui-manager/helm/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.deploy }}
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: {{ include "babylon-lab-ui-manager.serviceAccountName" . }}
6 | namespace: {{ include "babylon-lab-ui-manager.namespaceName" . }}
7 | labels:
8 | {{- include "babylon-lab-ui-manager.labels" . | nindent 4 }}
9 | {{ end }}
10 |
--------------------------------------------------------------------------------
/lab-ui-manager/kopf-opt.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | KOPF_OPTIONS="--log-format=json"
3 |
4 | # Restrict watch to operator namespace.
5 | KOPF_NAMESPACED=false
6 |
--------------------------------------------------------------------------------
/lab-ui-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 |
--------------------------------------------------------------------------------
/lab-ui-manager/requirements.txt:
--------------------------------------------------------------------------------
1 | pydantic==1.10.13
2 |
--------------------------------------------------------------------------------
/lab-ui-manager/user-configmap.resourceclaim.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: poolboy.gpte.redhat.com/v1
2 | kind: ResourceClaim
3 | metadata:
4 | name: guid-j8m2n-user1
5 | namespace: user-jkupfere-redhat-com
6 | spec:
7 | resources:
8 | - provider:
9 | apiVersion: poolboy.gpte.redhat.com/v1
10 | kind: ResourceProvider
11 | name: babylon-user-configmap
12 | namespace: poolboy
13 | template:
14 | metadata:
15 | labels:
16 | babylon.gpte.redhat.com/catalogItem: test-user
17 |
--------------------------------------------------------------------------------
/lab-ui-manager/user-configmap.resourcehandle.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: poolboy.gpte.redhat.com/v1
2 | kind: ResourceHandle
3 | metadata:
4 | name: guid-j8m2n-user1
5 | namespace: poolboy
6 | spec:
7 | resources:
8 | - provider:
9 | apiVersion: poolboy.gpte.redhat.com/v1
10 | kind: ResourceProvider
11 | name: babylon-user-configmap
12 | namespace: poolboy
13 | template:
14 | metadata:
15 | namespace: user-jkupfere-redhat-com
16 | labels:
17 | babylon.gpte.redhat.com/catalogItem: test-user
18 | data:
19 | foo: bar
20 |
--------------------------------------------------------------------------------
/lab-ui-manager/user-configmap.resourceprovider.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: poolboy.gpte.redhat.com/v1
2 | kind: ResourceProvider
3 | metadata:
4 | name: babylon-user-configmap
5 | namespace: poolboy
6 | spec:
7 | disableCreation: true
8 | matchIgnore:
9 | - /data(/.*)?
10 | - /metadata/namespace
11 | override:
12 | apiVersion: v1
13 | kind: ConfigMap
14 | metadata:
15 | name: user-{{ resource_handle.metadata.name[5:] }}
16 | data: {}
17 | template:
18 | enable: true
19 | updateFilters: []
20 | validation:
21 | openAPIV3Schema:
22 | type: object
23 | additionalProperties: false
24 | required:
25 | - metadata
26 | properties:
27 | metadata:
28 | type: object
29 | additionalProperties: false
30 | required:
31 | - labels
32 | properties:
33 | labels:
34 | type: object
35 | additionalProperties: false
36 | required:
37 | - babylon.gpte.redhat.com/catalogItem
38 | properties:
39 | babylon.gpte.redhat.com/catalogItem:
40 | type: string
41 |
--------------------------------------------------------------------------------
/notifier/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .odo/env
3 | .odo/odo-file-index.json
--------------------------------------------------------------------------------
/notifier/.s2i/bin/assemble:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | npm install -g npm@8.19.3
4 | npm install -g mjml@4.13.0
5 |
6 | exec /usr/libexec/s2i/assemble
--------------------------------------------------------------------------------
/notifier/Containerfile:
--------------------------------------------------------------------------------
1 | FROM quay.io/redhat-cop/python-kopf-s2i:v1.37
2 |
3 | USER root
4 |
5 | COPY . /tmp/src
6 |
7 | RUN dnf install -y ruby ruby-libs && \
8 | gem install asciidoctor && \
9 | rm -rf /tmp/src/.git* && \
10 | chown -R 1001 /tmp/src && \
11 | chgrp -R 0 /tmp/src && \
12 | chmod -R g+w /tmp/src && \
13 | cp -rp /tmp/src/.s2i/bin /tmp/scripts
14 |
15 | USER 1001
16 |
17 | RUN /tmp/scripts/assemble
18 |
19 | CMD ["/usr/libexec/s2i/run"]
20 |
--------------------------------------------------------------------------------
/notifier/README.adoc:
--------------------------------------------------------------------------------
1 | = Babylon notifier
2 |
3 | Email notification component
4 |
5 | == Manual Deployment
6 |
7 | . Create `client.crt` and `client.key` with SMTP client auth cert and key.
8 |
9 | . Create `values.yaml`:
10 | +
11 | ---------------------------
12 | redis:
13 | password: p4ssw0rd
14 | smtp:
15 | from: noreply@opentlc.com
16 | host: mx00.opentlc.com
17 | port: 19587
18 | ---------------------------
19 |
20 | . Deploy with helm template:
21 | +
22 | ---------------------------
23 | helm template helm \
24 | --values values.yaml \
25 | --set smtp.tls.crt="$(cat client.crt)" \
26 | --set smtp.tls.key="$(cat client.key)" \
27 | | oc apply -f -
28 | ---------------------------
29 | ```
30 |
31 |
--------------------------------------------------------------------------------
/notifier/build-template.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: template.openshift.io/v1
3 | kind: Template
4 | metadata:
5 | annotations:
6 | description: babylon-notifier deploy
7 | name: babylon-notifier-build
8 |
9 | parameters:
10 | - name: NAME
11 | value: babylon-notifier
12 | - name: GIT_REPO
13 | value: https://github.com/redhat-cop/babylon.git
14 | - name: GIT_REF
15 | value: main
16 |
17 | objects:
18 | - apiVersion: image.openshift.io/v1
19 | kind: ImageStream
20 | metadata:
21 | name: ${NAME}
22 | spec:
23 | lookupPolicy:
24 | local: false
25 |
26 | - apiVersion: v1
27 | kind: BuildConfig
28 | metadata:
29 | name: ${NAME}
30 | spec:
31 | output:
32 | to:
33 | kind: ImageStreamTag
34 | name: ${NAME}:latest
35 | postCommit: {}
36 | resources: {}
37 | runPolicy: Serial
38 | source:
39 | contextDir: notifier
40 | git:
41 | uri: ${GIT_REPO}
42 | ref: ${GIT_REF}
43 | strategy:
44 | type: Docker
45 | dockerStrategy:
46 | dockerfilePath: Containerfile
47 | forcePull: true
48 | triggers: []
49 |
--------------------------------------------------------------------------------
/notifier/helm/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | name: babylon-notifier
3 | description: A Helm chart for the babylon notifier component.
4 |
5 | # A chart can be either an 'application' or a 'library' chart.
6 | #
7 | # Application charts are a collection of templates that can be packaged into versioned archives
8 | # to be deployed.
9 | #
10 | # Library charts provide useful utilities or functions for the chart developer. They're included as
11 | # a dependency of application charts to inject those utilities and functions into the rendering
12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed.
13 | type: application
14 |
15 | # This is the chart version. This version number should be incremented each time you make changes
16 | # to the chart and its templates, including the app version.
17 | version: 0.8.3
18 |
19 | # This is the version number of the application being deployed. This version number should be
20 | # incremented each time you make changes to the application.
21 | appVersion: 0.8.3
22 |
--------------------------------------------------------------------------------
/notifier/helm/templates/namespace.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.namespace.create }}
2 | apiVersion: v1
3 | kind: Namespace
4 | metadata:
5 | name: {{ include "babylon-notifier.namespaceName" . }}
6 | {{ end }}
7 |
--------------------------------------------------------------------------------
/notifier/helm/templates/redis/pvc.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.redis.volume }}
2 | apiVersion: v1
3 | kind: PersistentVolumeClaim
4 | metadata:
5 | name: {{ include "babylon-notifier.redisName" . }}
6 | namespace: {{ include "babylon-notifier.namespaceName" . }}
7 | labels:
8 | {{- include "babylon-notifier.labels" . | nindent 4 }}
9 | spec:
10 | {{- .Values.redis.volume | nindent 2 }}
11 | {{ end }}
12 |
--------------------------------------------------------------------------------
/notifier/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 "babylon-notifier.redisName" . }}
6 | namespace: {{ include "babylon-notifier.namespaceName" . }}
7 | labels:
8 | {{- include "babylon-notifier.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 |
--------------------------------------------------------------------------------
/notifier/helm/templates/redis/service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: {{ include "babylon-notifier.redisName" . }}
5 | namespace: {{ include "babylon-notifier.namespaceName" . }}
6 | labels:
7 | {{- include "babylon-notifier.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 "babylon-notifier.redisSelectorLabels" . | nindent 4 }}
17 |
--------------------------------------------------------------------------------
/notifier/helm/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.deploy }}
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: {{ include "babylon-notifier.serviceAccountName" . }}
6 | namespace: {{ include "babylon-notifier.namespaceName" . }}
7 | labels:
8 | {{- include "babylon-notifier.labels" . | nindent 4 }}
9 | {{ end }}
10 |
--------------------------------------------------------------------------------
/notifier/helm/templates/smtp-secret.yaml:
--------------------------------------------------------------------------------
1 | {{- if (.Values.smtp.account).generateSecret }}
2 | apiVersion: v1
3 | kind: Secret
4 | metadata:
5 | name: {{ include "babylon-notifier.smtpSecret" . | quote }}
6 | namespace: {{ include "babylon-notifier.namespaceName" . }}
7 | labels:
8 | {{- include "babylon-notifier.labels" . | nindent 4 }}
9 | data:
10 | user: {{ required ".Values.smtp.account.username is required!" .Values.smtp.account.username | b64enc }}
11 | password: {{ required ".Values.smtp.account.password is required!" .Values.smtp.account.password | b64enc }}
12 | {{- end }}
13 |
--------------------------------------------------------------------------------
/notifier/helm/templates/tls-secret.yaml:
--------------------------------------------------------------------------------
1 | {{- if (.Values.smtp.tls).crt }}
2 | ---
3 | apiVersion: v1
4 | kind: Secret
5 | metadata:
6 | name: {{ .Values.smtp.tls.clientCertificateSecret | default (include "babylon-notifier.name" .) }}-tls
7 | namespace: {{ include "babylon-notifier.namespaceName" . }}
8 | labels:
9 | {{- include "babylon-notifier.labels" . | nindent 4 }}
10 | data:
11 | tls.crt: {{ .Values.smtp.tls.crt | b64enc }}
12 | tls.key: {{ required "smtp.tls.key is required when smtp.tls.crt is provided" .Values.smtp.tls.key | b64enc }}
13 | {{ end }}
14 |
--------------------------------------------------------------------------------
/notifier/kopf-opt.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | KOPF_OPTIONS="--log-format=json"
3 | KOPF_PEERING="babylon-notifier"
4 |
--------------------------------------------------------------------------------
/notifier/operator/catalog_namespace.py:
--------------------------------------------------------------------------------
1 | import kubernetes_asyncio
2 |
3 | from babylon import Babylon
4 |
5 | class CatalogNamespace:
6 | @classmethod
7 | async def get(cls, name):
8 | try:
9 | namespace = await Babylon.core_v1_api.read_namespace(name)
10 | return CatalogNamespace(namespace)
11 | except kubernetes_asyncio.client.rest.ApiException as e:
12 | if e.status == 404:
13 | return None
14 | else:
15 | raise
16 |
17 | def __init__(self, namespace):
18 | self.namespace = namespace
19 |
20 | @property
21 | def name(self):
22 | return self.namespace.metadata.name
23 |
24 | @property
25 | def display_name(self):
26 | return self.namespace.metadata.annotations.get('openshift.io/display-name', self.name)
27 |
--------------------------------------------------------------------------------
/notifier/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 | return True
8 |
9 | def configure_kopf_logging():
10 | objlogger = logging.getLogger('kopf.objects')
11 | objlogger.addFilter(suppress_handler_succeeded_messages)
12 |
--------------------------------------------------------------------------------
/notifier/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 |
--------------------------------------------------------------------------------
/notifier/operator/templates/provision-failed.mjml.j2:
--------------------------------------------------------------------------------
1 | {% extends "base.mjml.j2" %}
2 | {% block content %}
3 |
4 |
5 |
6 |
7 | Your {{ catalog_namespace.display_name }} service, {{ service_display_name }}, has failed to provision.
8 | {% if have_attachments %}
9 | Please see attached Ansible log.
10 | {% endif %}
11 |
12 |
13 | {% if service_url %}
14 | You may manage your {{ catalog_namespace.display_name }} service at:
15 | {{ service_url }}.
16 | {% endif %}
17 |
18 |
19 |
20 |
21 | {% endblock content %}
--------------------------------------------------------------------------------
/notifier/operator/templates/retirement-scheduled.mjml.j2:
--------------------------------------------------------------------------------
1 | {% extends "base.mjml.j2" %}
2 | {% block content %}
3 |
4 |
5 |
6 |
7 | Reminder:
8 | Your environment will expire and be deleted in {{ retirement_timedelta_humanized }} at {{ retirement_timestamp }}.
9 |
10 | {% if service_url %}
11 | You may manage your {{ catalog_namespace.display_name }} service at:
12 | {{ service_url }}.
13 | {% endif %}
14 |
15 |
16 |
17 |
18 | {% endblock content %}
--------------------------------------------------------------------------------
/notifier/operator/templates/service-deleted.mjml.j2:
--------------------------------------------------------------------------------
1 | {% extends "base.mjml.j2" %}
2 | {% block content %}
3 |
4 |
5 |
6 |
7 | Your {{ catalog_namespace.display_name }} service {{ service_display_name }} has been deleted.
8 |
9 | To conserve resources data on these systems is not archived and cannot be retrieved.
10 | We apologize for any inconvenience this may cause.
11 |
12 | Thank you for using {{ catalog_namespace.display_name }}.
13 |
14 | {% if survey_link %}
15 | We would love your feedback on your demo/lab, please fill out our short Survey (click here) to help us improve your experience.
16 | {% endif %}
17 |
18 |
19 |
20 |
21 | {% endblock content %}
--------------------------------------------------------------------------------
/notifier/operator/templates/start-complete.mjml.j2:
--------------------------------------------------------------------------------
1 | {% extends "base.mjml.j2" %}
2 | {% block content %}
3 |
4 |
5 |
6 |
7 | Your {{ catalog_namespace.display_name }} service {{ service_display_name }} has started.
8 |
9 |
10 | NOTICE:
11 |
12 | {% if stop_timestamp < retirement_timestamp %}
13 | - Your environment will be stopped in {{ stop_timedelta_humanized }} at {{ stop_timestamp }}.
14 | {% endif %}
15 | - Your environment will expire and be deleted in {{ retirement_timedelta_humanized }} at {{ retirement_timestamp }}.
16 |
17 |
18 |
19 | {% if service_url %}
20 | You may manage your {{ catalog_namespace.display_name }} service at:
21 | {{ service_url }}.
22 | {% endif %}
23 |
24 |
25 |
26 |
27 | {% endblock content %}
28 |
--------------------------------------------------------------------------------
/notifier/operator/templates/start-failed.mjml.j2:
--------------------------------------------------------------------------------
1 | {% extends "base.mjml.j2" %}
2 | {% block content %}
3 |
4 |
5 |
6 |
7 | Your {{ catalog_namespace.display_name }} service {{ service_display_name }} failed to start.
8 | {% if have_attachments %}
9 | Please see attached Ansible log.
10 | {% endif %}
11 |
12 |
13 | {% if service_url %}
14 | You may manage your {{ catalog_namespace.display_name }} service at:
15 | {{ service_url }}.
16 | {% endif %}
17 |
18 |
19 |
20 |
21 | {% endblock content %}
--------------------------------------------------------------------------------
/notifier/operator/templates/stop-complete.mjml.j2:
--------------------------------------------------------------------------------
1 | {% extends "base.mjml.j2" %}
2 | {% block content %}
3 |
4 |
5 |
6 |
7 | Your {{ catalog_namespace.display_name }} service {{ service_display_name }} has stopped.
8 |
9 | {% if service_url %}
10 | You may manage your {{ catalog_namespace.display_name }} service at:
11 | {{ service_url }}.
12 | {% endif %}
13 |
14 |
15 |
16 |
17 | {% endblock content %}
--------------------------------------------------------------------------------
/notifier/operator/templates/stop-failed.mjml.j2:
--------------------------------------------------------------------------------
1 | {% extends "base.mjml.j2" %}
2 | {% block content %}
3 |
4 |
5 |
6 |
7 | Your {{ catalog_namespace.display_name }} service {{ service_display_name }} failed to stop.
8 | {% if have_attachments %}
9 | Please see attached Ansible log.
10 | {% endif %}
11 |
12 |
13 | {% if service_url %}
14 | You may manage your {{ catalog_namespace.display_name }} service at:
15 | {{ service_url }}.
16 | {% endif %}
17 |
18 |
19 |
20 |
21 | {% endblock content %}
--------------------------------------------------------------------------------
/notifier/operator/templates/stop-scheduled.mjml.j2:
--------------------------------------------------------------------------------
1 | {% extends "base.mjml.j2" %}
2 | {% block content %}
3 |
4 |
5 |
6 |
7 | Reminder:
8 | Your environment will be stopped in {{ stop_timedelta_humanized }} at {{ stop_timestamp }}.
9 |
10 | {% if service_url %}
11 | You may manage your {{ catalog_namespace.display_name }} service at:
12 | {{ service_url }}.
13 | {% endif %}
14 |
15 |
16 |
17 |
18 | {% endblock content %}
--------------------------------------------------------------------------------
/notifier/operator/templates/wrapper.mjml.j2:
--------------------------------------------------------------------------------
1 | {% extends "base.mjml.j2" %}
2 | {% block content %}
3 |
4 |
5 |
6 |
7 | {{ htmlContent }}
8 |
9 |
10 |
11 |
12 | {% endblock content %}
--------------------------------------------------------------------------------
/notifier/requirements.txt:
--------------------------------------------------------------------------------
1 | aiohttp==3.10.11
2 | aiosmtplib==3.0.0
3 | html2text==2020.1.16
4 | humanize==4.8.0
5 | Jinja2==3.1.6
6 | pydantic==2.4.1
7 | pytimeparse==1.1.8
8 | redis==5.0.1
9 |
--------------------------------------------------------------------------------
/openshift/config/common/helm/babylon-admin:
--------------------------------------------------------------------------------
1 | ./../../../../admin/helm
--------------------------------------------------------------------------------
/openshift/config/common/helm/babylon-agnosticv-operator:
--------------------------------------------------------------------------------
1 | ../../../../agnosticv-operator/helm
--------------------------------------------------------------------------------
/openshift/config/common/helm/babylon-catalog:
--------------------------------------------------------------------------------
1 | ../../../../catalog/helm
--------------------------------------------------------------------------------
/openshift/config/common/helm/babylon-catalog-manager:
--------------------------------------------------------------------------------
1 | ../../../../catalog-manager/helm
--------------------------------------------------------------------------------
/openshift/config/common/helm/babylon-config/Chart.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v2
3 | name: babylon-config
4 | description: Babylon Configuration
5 | type: application
6 | version: 0.0.1
7 | appVersion: 0.0.1
8 |
--------------------------------------------------------------------------------
/openshift/config/common/helm/babylon-config/values.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | #
3 | # New namespace will be created if anarchy.namespaces[].create is boolean 'true' or
4 | # not defined.
5 |
6 |
7 | anarchy:
8 | apiGroup: anarchy.gpte.redhat.com
9 | namespaces:
10 | - name: anarchy-operator
11 | create: true
12 | secrets: []
13 |
14 | poolboy:
15 | apiGroup: poolboy.gpte.redhat.com
16 | namespace: poolboy
17 |
18 | catalogNamespaces: []
19 |
20 | crossClusterBackup:
21 | enable: false
22 | clusterRoleName: babylon-cross-cluster-backup
23 | namespace: babylon-cross-cluster-backup
24 | replik8sVersion: latest
25 |
26 | operatorNamespace: openshift-operators
27 |
--------------------------------------------------------------------------------
/openshift/config/common/helm/babylon-cost-tracker:
--------------------------------------------------------------------------------
1 | ../../../../cost-tracker/helm
--------------------------------------------------------------------------------
/openshift/config/common/helm/babylon-lab-ui-manager:
--------------------------------------------------------------------------------
1 | ../../../../lab-ui-manager/helm
--------------------------------------------------------------------------------
/openshift/config/common/helm/babylon-notifier:
--------------------------------------------------------------------------------
1 | ../../../../notifier/helm
--------------------------------------------------------------------------------
/openshift/config/common/helm/babylon-ratings:
--------------------------------------------------------------------------------
1 | ../../../../ratings/helm
--------------------------------------------------------------------------------
/openshift/config/common/helm/babylon-workshop-manager:
--------------------------------------------------------------------------------
1 | ../../../../workshop-manager/helm
--------------------------------------------------------------------------------
/openshift/config/common/templates/anarchy-install.yaml.j2:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: operators.coreos.com/v1alpha1
3 | kind: CatalogSource
4 | metadata:
5 | name: anarchy-operator
6 | namespace: openshift-marketplace
7 | spec:
8 | displayName: Anarchy Operator
9 | image: quay.io/redhat-cop/anarchy-operator:catalog-{{ babylon_anarchy_version }}
10 | sourceType: grpc
11 | ---
12 | apiVersion: operators.coreos.com/v1alpha1
13 | kind: Subscription
14 | metadata:
15 | name: anarchy-operator
16 | namespace: openshift-operators
17 | spec:
18 | channel: "stable"
19 | installPlanApproval: Automatic
20 | name: anarchy-operator
21 | source: anarchy-operator
22 | sourceNamespace: openshift-marketplace
23 |
--------------------------------------------------------------------------------
/openshift/config/common/templates/anarchy-k8s-config/anarchysubjects/babylon.yaml.j2:
--------------------------------------------------------------------------------
1 | apiVersion: anarchy.gpte.redhat.com/v1
2 | kind: AnarchySubject
3 | metadata:
4 | name: babylon
5 | spec:
6 | governor: gitops
7 | vars:
8 | # Configuration source vars
9 | babylon_repo_url: {{ babylon_repo_url | to_json }}
10 | babylon_repo_version: {{ babylon_repo_version | to_json }}
11 | {% raw %}
12 | k8s_config_sources:
13 | - name: babylon
14 | git:
15 | accept_hostkey: true
16 | repo: "{{ babylon_repo_url }}"
17 | version: "{{ babylon_repo_version }}"
18 | base_path: openshift/config
19 | {% endraw %}
20 |
--------------------------------------------------------------------------------
/openshift/config/env/dev/main.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # This file should only contain variables specific to dev environments.
3 | # The values for these variables do not get promoted from dev to test or prod.
4 |
--------------------------------------------------------------------------------
/openshift/config/env/prod/main.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # This file should only contain variables specific to prod environments.
3 |
--------------------------------------------------------------------------------
/openshift/config/env/test/main.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # This file should only contain variables specific to test environments.
3 | # The values for these variables do not get promoted from to prod.
4 |
--------------------------------------------------------------------------------
/ratings/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .odo
--------------------------------------------------------------------------------
/ratings/.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
--------------------------------------------------------------------------------
/ratings/.s2i/bin/run:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 |
4 | if [ "${RATINGS_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
--------------------------------------------------------------------------------
/ratings/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM registry.access.redhat.com/ubi8/python-39: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 |
--------------------------------------------------------------------------------
/ratings/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-ratings/
9 | . ~/virtualenv/babylon-ratings/bin/activate
10 | pip install -r requirements.txt
11 | -----------------------------------------------
12 |
13 | === Running in Development
14 |
15 | ==== Export environment variables for database connection
16 |
17 | You can get the values for these from the Bitwarden Password Manager and the
18 | `Demo Reporting` collection.
19 | -----------------------------------------------
20 | export DB_HOSTNAME=<>
21 | export DB_USERNAME=<>
22 | export DB_PASSWORD=<>
23 | export DB_NAME=<>
24 | export DB_PORT=<>
25 | -----------------------------------------------
26 |
27 |
28 | Commands each time to start:
29 |
30 | ---------------------------------
31 | . ~/virtualenv/babylon-ratings/bin/activate
32 | uvicorn app:app --host 0.0.0.0 --port 8080 --lifespan on --log-level info --log-config logconfig.yaml --reload
33 | ---------------------------------
34 |
--------------------------------------------------------------------------------
/ratings/api/babylon.py:
--------------------------------------------------------------------------------
1 | import kubernetes_asyncio
2 | import os
3 |
4 |
5 | class Babylon():
6 | babylon_domain = os.environ.get('BABYLON_DOMAIN', 'babylon.gpte.redhat.com')
7 | babylon_api_version = os.environ.get('BABYLON_API_VERSION', 'v1')
8 |
9 | @classmethod
10 | async def on_cleanup(cls):
11 | await cls.core_v1_api.api_client.close()
12 | await cls.custom_objects_api.api_client.close()
13 |
14 | @classmethod
15 | async def on_startup(cls):
16 | if os.path.exists('/run/secrets/kubernetes.io/serviceaccount'):
17 | kubernetes_asyncio.config.load_incluster_config()
18 | else:
19 | await kubernetes_asyncio.config.load_kube_config()
20 |
21 | cls.core_v1_api = kubernetes_asyncio.client.CoreV1Api()
22 | cls.custom_objects_api = kubernetes_asyncio.client.CustomObjectsApi()
23 |
--------------------------------------------------------------------------------
/ratings/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 | "level": record.levelname,
10 | "message": record.getMessage()
11 | }
12 | return json.dumps(log_data)
13 |
--------------------------------------------------------------------------------
/ratings/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 |
--------------------------------------------------------------------------------
/ratings/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 |
--------------------------------------------------------------------------------
/ratings/api/routers/__init__.py:
--------------------------------------------------------------------------------
1 | from fastapi import Query
2 | from . import ratings
3 | from . import bookmarks
4 |
5 | def get_pagination_params(
6 | page: int = Query(1, description="Número da página a ser recuperada"),
7 | per_page: int = Query(10, description="Número de itens por página")
8 | ) -> dict:
9 | return {"page": page, "per_page": per_page}
10 |
--------------------------------------------------------------------------------
/ratings/api/routers/pagination.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 |
--------------------------------------------------------------------------------
/ratings/api/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | from .catalog_item import CatalogItemSchema
2 | from .provision import ProvisionSchema
3 | from .purpose import PurposeSchema
4 | from .ratings import RatingsListSchema, RatingSchema, RatingCreateSchema, RatingProvisionCreateSchema, CatalogItemRatingAverageSchema
5 | from .request import RequestSchema
6 | from .user import UserSchema
7 | from .workshop import WorkshopSchema, WorkshopRequestSchema
8 | from .bookmarks import BookmarkSchema, BookmarkRequestSchema, BookmarkListResponseSchema
--------------------------------------------------------------------------------
/ratings/api/schemas/purpose.py:
--------------------------------------------------------------------------------
1 | from typing import List, Optional
2 | from pydantic import BaseModel, Field
3 | from datetime import datetime
4 |
5 |
6 | class PurposeSchema(BaseModel):
7 | id: int = Field(..., description="The unique identifier for the purpose.")
8 | activity: str = Field(..., description="The activity of the purpose.")
9 | purpose: str = Field(..., description="The purpose of the purpose.")
10 | created_at: Optional[datetime] = Field(None, description="The created at of the purpose.")
11 | updated_at: Optional[datetime] = Field(None, description="The updated at of the purpose.")
12 |
13 | class Config:
14 | from_attributes = True
15 |
--------------------------------------------------------------------------------
/ratings/helm/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | name: babylon-ratings
3 | description: A Helm chart for the babylon ratings component.
4 | type: application
5 | version: 1.0.10
6 | appVersion: 1.0.10
7 |
--------------------------------------------------------------------------------
/ratings/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-ratings.namespaceName" . }}
7 | labels:
8 | {{- include "babylon-ratings.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 |
--------------------------------------------------------------------------------
/ratings/helm/templates/namespace.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.namespace.create }}
2 | apiVersion: v1
3 | kind: Namespace
4 | metadata:
5 | name: {{ include "babylon-ratings.namespaceName" . }}
6 | {{ end }}
7 |
--------------------------------------------------------------------------------
/ratings/helm/templates/service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: {{ include "babylon-ratings.name" . }}
5 | namespace: {{ include "babylon-ratings.namespaceName" . }}
6 | labels:
7 | {{- include "babylon-ratings.labels" . | nindent 4 }}
8 | spec:
9 | type: ClusterIP
10 | ports:
11 | - name: ratings-api
12 | port: 8080
13 | protocol: TCP
14 | targetPort: 8080
15 | selector:
16 | {{- include "babylon-ratings.selectorLabels" . | nindent 4 }}
--------------------------------------------------------------------------------
/ratings/helm/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.deploy }}
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: {{ include "babylon-ratings.serviceAccountName" . }}
6 | namespace: {{ include "babylon-ratings.namespaceName" . }}
7 | labels:
8 | {{- include "babylon-ratings.labels" . | nindent 4 }}
9 | {{ end }}
10 |
--------------------------------------------------------------------------------
/ratings/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 |
--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------
1 | sonar.projectKey=com.redhat.rhpds.redhat-cop.babylon
2 | sonar.qualitygate.wait=true
3 |
--------------------------------------------------------------------------------
/test/README.md:
--------------------------------------------------------------------------------
1 | # Babylon Tests
2 |
--------------------------------------------------------------------------------
/tools/babylon-status/governor_versions.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import sys
4 | import kubernetes
5 | from pprint import pprint
6 |
7 | kubernetes.config.load_kube_config()
8 |
9 | custom_objects_api = kubernetes.client.CustomObjectsApi()
10 |
11 | response_governors = custom_objects_api.list_cluster_custom_object(
12 | 'anarchy.gpte.redhat.com',
13 | 'v1',
14 | 'anarchygovernors')
15 |
16 |
17 | governors = response_governors['items']
18 |
19 | versions = {}
20 |
21 | for governor in governors:
22 | name = governor['metadata']['name']
23 | if 'ansibleGalaxyRequirements' in governor['spec']:
24 | if 'roles' in governor['spec']['ansibleGalaxyRequirements']:
25 | for role in governor['spec']['ansibleGalaxyRequirements']['roles']:
26 | if role['name'] == 'babylon_anarchy_governor':
27 | if role['version'] not in versions:
28 | versions[role['version']] = 1
29 | else:
30 | versions[role['version']] += 1
31 |
32 |
33 | # Print versions summary using prettyprint
34 |
35 | pprint(versions)
36 |
--------------------------------------------------------------------------------
/workshop-manager/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .odo/env
3 | .odo/odo-file-index.json
--------------------------------------------------------------------------------
/workshop-manager/Containerfile:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/workshop-manager/README.adoc:
--------------------------------------------------------------------------------
1 | = Workshop Provisioner
2 |
3 | Component to deploy services for workshops.
4 |
--------------------------------------------------------------------------------
/workshop-manager/build-template.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: template.openshift.io/v1
3 | kind: Template
4 | metadata:
5 | annotations:
6 | description: babylon-workshop-manager deploy
7 | name: babylon-workshop-manager-build
8 |
9 | parameters:
10 | - name: NAME
11 | value: babylon-workshop-manager
12 | - name: GIT_REPO
13 | value: https://github.com/redhat-cop/babylon.git
14 | - name: GIT_REF
15 | value: main
16 |
17 | objects:
18 | - apiVersion: image.openshift.io/v1
19 | kind: ImageStream
20 | metadata:
21 | name: ${NAME}
22 | spec:
23 | lookupPolicy:
24 | local: false
25 |
26 | - apiVersion: v1
27 | kind: BuildConfig
28 | metadata:
29 | name: ${NAME}
30 | spec:
31 | output:
32 | to:
33 | kind: ImageStreamTag
34 | name: ${NAME}:latest
35 | postCommit: {}
36 | resources: {}
37 | runPolicy: Serial
38 | source:
39 | contextDir: workshop-manager
40 | git:
41 | uri: ${GIT_REPO}
42 | ref: ${GIT_REF}
43 | strategy:
44 | type: Source
45 | dockerStrategy:
46 | dockerfilePath: Containerfile
47 | forcePull: true
48 | triggers: []
49 |
--------------------------------------------------------------------------------
/workshop-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-workshop-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-workshop-manager-dev
35 | version: 1.0.0
36 | schemaVersion: 2.0.0
37 |
--------------------------------------------------------------------------------
/workshop-manager/helm/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | name: babylon-workshop-manager
3 | description: A Helm chart for the babylon lab ui manager component.
4 | type: application
5 | version: 0.8.3
6 | appVersion: 0.8.3
7 |
--------------------------------------------------------------------------------
/workshop-manager/helm/templates/namespace.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.namespace.create }}
2 | apiVersion: v1
3 | kind: Namespace
4 | metadata:
5 | name: {{ include "babylon-workshop-manager.namespaceName" . }}
6 | {{ end }}
7 |
--------------------------------------------------------------------------------
/workshop-manager/helm/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.deploy }}
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: {{ include "babylon-workshop-manager.serviceAccountName" . }}
6 | namespace: {{ include "babylon-workshop-manager.namespaceName" . }}
7 | labels:
8 | {{- include "babylon-workshop-manager.labels" . | nindent 4 }}
9 | {{ end }}
10 |
--------------------------------------------------------------------------------
/workshop-manager/kopf-opt.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | KOPF_NAMESPACED=false
3 |
--------------------------------------------------------------------------------
/workshop-manager/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 | return True
8 |
9 | def configure_kopf_logging():
10 | objlogger = logging.getLogger('kopf.objects')
11 | objlogger.addFilter(suppress_handler_succeeded_messages)
12 |
--------------------------------------------------------------------------------
/workshop-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 |
--------------------------------------------------------------------------------
/workshop-manager/operator/labuserinterface.py:
--------------------------------------------------------------------------------
1 | class LabUserInterface:
2 | def __init__(self, definition=None, url=None):
3 | if definition:
4 | self.url = definition.get('url')
5 | else:
6 | self.url = url
7 |
8 | def serialize(self):
9 | ret = dict(url=self.url)
10 | return ret
11 |
--------------------------------------------------------------------------------
/workshop-manager/operator/resourceprovider.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from copy import deepcopy
4 | from datetime import datetime, timezone
5 |
6 | import kubernetes_asyncio
7 |
8 | from babylon import Babylon
9 | from k8sobject import K8sObject
10 |
11 | class ResourceProvider(K8sObject):
12 | api_group = Babylon.poolboy_domain
13 | api_version = Babylon.poolboy_api_version
14 | kind = 'ResourceProvider'
15 | plural = 'resourceproviders'
16 |
17 | @property
18 | def parameters(self):
19 | return self.definition.get('spec', {}).get('parameters', [])
20 |
21 | def has_parameter(self, name):
22 | for parameter in self.parameters:
23 | if name == parameter.get('name'):
24 | return True
25 | return False
26 |
--------------------------------------------------------------------------------
/workshop-manager/requirements.txt:
--------------------------------------------------------------------------------
1 | pydantic==1.10.13
2 |
--------------------------------------------------------------------------------