Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AGENT-1120: Initial Assisted disconnected UI #2789

Merged
merged 4 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions .github/workflows/push-to-master-disconnected.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
name: Assisted Disconnected UI - Push to master or release tag

on:
push:
branches:
- master
tags:
- 'v*-dis'

env:
QUAY_ORG: quay.io/edge-infrastructure
QUAY_REPO: assisted-disconnected-ui

jobs:
preflight-check:
# Prevents running the workflow when a brand-new tag points to the same commit as the master branch
runs-on: ubuntu-latest
outputs:
skip: ${{ steps.check.outputs.skip }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Check if a tag points to the same commit as the master branch
id: check
run: |
if [[ "${GITHUB_REF_TYPE}" == "tag" ]] && [[ "${GITHUB_SHA}" == "$(git rev-parse origin/master)" ]]; then
skip=true
else
skip=false
fi
echo "skip=${skip}" >> $GITHUB_OUTPUT
echo "skip=${skip}"

publish-assisted-disconnected-ui:
needs: preflight-check
if: needs.preflight-check.outputs.skip == 'false'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Generate AIUI_APP_VERSION
run: |
AIUI_APP_VERSION=latest
if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
AIUI_APP_VERSION=${GITHUB_REF_NAME}
fi
echo "AIUI_APP_VERSION=${AIUI_APP_VERSION}" >> $GITHUB_ENV
echo "AIUI_APP_VERSION=${AIUI_APP_VERSION}"

- name: Generate tags
id: generate-tags
run: |
tags=( latest-${GITHUB_SHA} latest )
if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
tags+=( ${GITHUB_REF_NAME} )
if [[ ! "${GITHUB_REF_NAME}" =~ -cim$ ]]; then
tags+=( staging-released )
fi
fi
echo "tags=${tags[@]}" >> $GITHUB_OUTPUT
echo "tags=${tags[@]}"

- name: Build
id: build
uses: redhat-actions/buildah-build@v2
with:
image: ${{ env.QUAY_REPO }}
tags: ${{ steps.generate-tags.outputs.tags }}
labels: |
org.openshift-assisted.github.repository=${{ github.repository }}
org.openshift-assisted.github.actor=${{ github.actor }}
org.openshift-assisted.github.run_id=${{ github.run_id }}
org.openshift-assisted.github.sha=${{ github.sha }}
org.openshift-assisted.github.ref_name=${{ github.ref_name }}
build-args: |
AIUI_APP_VERSION=${{ env.AIUI_APP_VERSION }}
AIUI_APP_GIT_SHA=${{ github.sha }}
AIUI_APP_IMAGE_REPO=${{ env.QUAY_ORG }}/${{ env.QUAY_REPO }}
containerfiles: apps/assisted-disconnected-ui/Containerfile
context: .

- name: Push to Quay.io
id: push
uses: redhat-actions/push-to-registry@v2.7
with:
image: ${{ steps.build.outputs.image }}
tags: ${{ steps.build.outputs.tags }}
registry: ${{ env.QUAY_ORG }}
username: ${{ secrets.QUAY_EDGE_INFRA_ROBOT_USERNAME }}
password: ${{ secrets.QUAY_EDGE_INFRA_ROBOT_PASSWORD }}
1 change: 1 addition & 0 deletions .github/workflows/push-to-master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ on:
tags:
- 'v*'
- '!v*-cim'
- '!v*-virt'

env:
QUAY_ORG: quay.io/edge-infrastructure
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ package-lock.json
# Ignored apps
apps/*
!apps/assisted-ui
!apps/assisted-disconnected-ui
2 changes: 2 additions & 0 deletions apps/assisted-disconnected-ui/.containerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
**/node_modules/
**/build/
55 changes: 55 additions & 0 deletions apps/assisted-disconnected-ui/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/** @type {import('eslint').ESLint.ConfigData} */
module.exports = {
overrides: [
{
files: ['./vite.config.ts'],
extends: ['@openshift-assisted/eslint-config'],
env: {
browser: false,
},
parserOptions: {
tsconfigRootDir: __dirname,
},
rules: {
'no-console': 'off',
},
},
{
files: ['./src/**/*.{ts,tsx}'],
extends: ['@openshift-assisted/eslint-config', 'plugin:react/jsx-runtime'],
parserOptions: {
tsconfigRootDir: __dirname,
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true,
},
rules: {
'no-restricted-imports': [
'error',
{
paths: [
{
name: 'react-i18next',
importNames: ['useTranslation'],
message:
'Import `useTranslation` from `lib/common/hooks/use-translation-wrapper.ts` instead',
},
{
name: '@openshift-assisted/ui-lib',
message: 'Import from `@openshift-assisted/ui-lib/ocm` instead',
},
{
name: '@patternfly/react-icons',
message:
'Import using full path `@patternfly/react-icons/dist/js/icons/<icon>` instead',
},
{
name: '@patternfly/react-tokens',
message:
'Import using full path `@patternfly/react-tokens/dist/js/<token>` instead',
},
],
},
],
},
},
],
};
1 change: 1 addition & 0 deletions apps/assisted-disconnected-ui/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
24 changes: 24 additions & 0 deletions apps/assisted-disconnected-ui/Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM registry.access.redhat.com/ubi9/nodejs-18-minimal:latest as ui-build
USER root
RUN microdnf install -y rsync git

WORKDIR /app
COPY --chown=1001:0 / /app
RUN ls /app
ENV NODE_OPTIONS='--max-old-space-size=8192'
RUN git config --global --add safe.directory /app
RUN npm install -g corepack@0.24.1
RUN yarn install --immutable && yarn build:all

FROM registry.access.redhat.com/ubi9/go-toolset:1.21 as proxy-build
WORKDIR /app
COPY apps/assisted-disconnected-ui/proxy /app
USER 0
RUN go build

FROM registry.access.redhat.com/ubi9/ubi-micro
COPY --from=ui-build /app/apps/assisted-disconnected-ui/build /app/proxy/dist
COPY --from=proxy-build /app/assisted-disconnected-ui /app/proxy
WORKDIR /app/proxy
EXPOSE 8080
CMD ./assisted-disconnected-ui
12 changes: 12 additions & 0 deletions apps/assisted-disconnected-ui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# The Assisted Installer Disconnected User Interface

## Setting up a local dev-environment

- Start [assisted-service](https://github.com/openshift/assisted-service). You can run it
[locally via podman](https://github.com/openshift/assisted-service/tree/master/deploy/podman)

- Start UI

```bash
AIUI_APP_API_URL=<assised_service_url> yarn start:assisted_disconnected_ui
```
14 changes: 14 additions & 0 deletions apps/assisted-disconnected-ui/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<link rel="stylesheet" href="/src/styles.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Assisted Installer</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
64 changes: 64 additions & 0 deletions apps/assisted-disconnected-ui/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"dependencies": {
"@openshift-assisted/ui-lib": "workspace:*",
"@openshift-console/dynamic-plugin-sdk": "0.0.3",
"@patternfly/patternfly": "5.2.0",
"@patternfly/react-code-editor": "5.2.0",
"@patternfly/react-core": "5.2.0",
"@patternfly/react-icons": "5.2.0",
"@patternfly/react-styles": "5.2.0",
"@patternfly/react-table": "5.2.0",
"@patternfly/react-tokens": "5.2.0",
"@reduxjs/toolkit": "^1.9.1",
"@sentry/browser": "^7.119",
"axios": ">=0.22.0 <2.0.0",
"i18next": "^20.4.0",
"i18next-browser-languagedetector": "^6.1.2",
"lodash": "^4",
"monaco-editor": "^0.44.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^11.11.4",
"react-monaco-editor": "^0.55.0",
"react-redux": "^8.0.5",
"react-router-dom": "^5.3.3",
"react-router-dom-v5-compat": "^6.21.2",
"react-tagsinput": "^3.20",
"redux": "^4",
"uuid": "^8.1",
"yup": "^1.4.0"
},
"description": "A stand-alone web UI for the disconnected environments",
"devDependencies": {
"@tsconfig/vite-react": "^1.0.1",
"@types/react": "17.0.x",
"@vitejs/plugin-react-swc": "^3.0.1",
"concurrently": "^8.2.2",
"nodemon": "^3.0.3",
"vite": "^4.5.6",
"vite-plugin-environment": "^1.1.3"
},
"overrides": {
"@patternfly/react-core": {
"attr-accept": "2.2.2"
}
},
"engines": {
"node": ">=14"
},
"license": "Apache-2.0",
"name": "@openshift-assisted/assisted-disconnected-ui",
"private": true,
"scripts": {
"build": "vite build -c vite.config.ts",
"check_types": "yarn run -T tsc --noEmit",
"clean": "yarn run -T rimraf node_modules build",
"preview": "vite preview -c vite.config.ts",
"serve": "concurrently \"vite serve -c vite.config.ts\" \"cd proxy && nodemon --watch './**/*' --exec 'go run' app.go --signal SIGTERM\"",
"format": "yarn run -T prettier --cache --check . \"!build\"",
"fix-code-style": "yarn lint --fix && yarn format --write",
"lint": "yarn run -T eslint --cache --cache-location node_modules/.cache/eslint/.eslint-cache ."
},
"type": "module",
"version": "1.0.0"
}
61 changes: 61 additions & 0 deletions apps/assisted-disconnected-ui/proxy/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package main

import (
"crypto/tls"
"net/http"
"time"

"github.com/gorilla/mux"

"github.com/openshift-assisted/assisted-disconnected-ui/bridge"
"github.com/openshift-assisted/assisted-disconnected-ui/config"
"github.com/openshift-assisted/assisted-disconnected-ui/log"
"github.com/openshift-assisted/assisted-disconnected-ui/server"
)

func main() {
tlsConfig, err := bridge.GetTlsConfig()
if err != nil {
panic(err)
}

log := log.InitLogs()
router := mux.NewRouter()

apiHandler := bridge.NewAssistedAPIHandler(tlsConfig)
router.PathPrefix("/api/{forward:.*}").Handler(apiHandler)

spa := server.SpaHandler{}
router.PathPrefix("/").Handler(server.GzipHandler(spa))

var serverTlsconfig *tls.Config

if config.TlsKeyPath != "" && config.TlsCertPath != "" {
cert, err := tls.LoadX509KeyPair(config.TlsCertPath, config.TlsKeyPath)
if err != nil {
panic(err)
}
serverTlsconfig = &tls.Config{
Certificates: []tls.Certificate{cert},
}

}

srv := &http.Server{
Handler: router,
Addr: config.BridgePort,
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
}

log.Info("Proxy running at", config.BridgePort)

if serverTlsconfig != nil {
srv.TLSConfig = serverTlsconfig
log.Info("Running as HTTPS")
log.Fatal(srv.ListenAndServeTLS("", ""))
} else {
log.Fatal(srv.ListenAndServe())
}

}
35 changes: 35 additions & 0 deletions apps/assisted-disconnected-ui/proxy/bridge/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package bridge

import (
"crypto/tls"
"crypto/x509"
"errors"
"os"

"github.com/openshift-assisted/assisted-disconnected-ui/config"
log "github.com/sirupsen/logrus"
)

func GetTlsConfig() (*tls.Config, error) {
tlsConfig := &tls.Config{}

if config.ApiInsecure == "true" {
log.Warn("Using InsecureSkipVerify for API communication")
tlsConfig.InsecureSkipVerify = true
}

_, err := os.Stat("../certs/ca.crt")
if errors.Is(err, os.ErrNotExist) {
return tlsConfig, nil
}
caCert, err := os.ReadFile("../certs/ca.crt")
if err != nil {
return nil, err
}

caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)

tlsConfig.RootCAs = caCertPool
return tlsConfig, nil
}
Loading
Loading