diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 88c06f6793..3b745ff4f8 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -35,7 +35,6 @@ jobs: save-orchestrator: ${{ steps.calculate-dependencies.outputs.save-orchestrator }} save-orchestrator-common: ${{ steps.calculate-dependencies.outputs.save-orchestrator-common }} save-preprocessor: ${{ steps.calculate-dependencies.outputs.save-preprocessor }} - save-sandbox: ${{ steps.calculate-dependencies.outputs.save-sandbox }} test-analysis-core: ${{ steps.calculate-dependencies.outputs.test-analysis-core }} test-utils: ${{ steps.calculate-dependencies.outputs.test-utils }} steps: @@ -87,8 +86,6 @@ jobs: - save-orchestrator-common/** save-preprocessor: - save-preprocessor/** - save-sandbox: - - save-sandbox/** test-analysis-core: - test-analysis-core/** test-utils: @@ -118,7 +115,6 @@ jobs: save_frontend=$(( $save_cloud_common + $save_frontend_common + ${{ steps.git-changed-files.outputs.save-frontend_all_changed_files_count }} )) save_orchestrator=$(( $save_cloud_common + $save_orchestrator_common + $test_utils + ${{ steps.git-changed-files.outputs.save-orchestrator_all_changed_files_count }} )) save_preprocessor=$(( $save_cloud_common + $test_utils + ${{ steps.git-changed-files.outputs.save-preprocessor_all_changed_files_count }} )) - save_sandbox=$(( $save_cloud_common + $authentication_service + $test_utils + ${{ steps.git-changed-files.outputs.save-sandbox_all_changed_files_count }} )) echo "api-gateway=$api_gateway" >> "$GITHUB_OUTPUT" echo "authentication-service=$authentication_service" >> "$GITHUB_OUTPUT" @@ -137,7 +133,6 @@ jobs: echo "save-orchestrator=$save_orchestrator" >> "$GITHUB_OUTPUT" echo "save-orchestrator-common=$save_orchestrator_common" >> "$GITHUB_OUTPUT" echo "save-preprocessor=$save_preprocessor" >> "$GITHUB_OUTPUT" - echo "save-sandbox=$save_sandbox" >> "$GITHUB_OUTPUT" echo "test-analysis-core=$test_analysis_core" >> "$GITHUB_OUTPUT" echo "test-utils=$test_utils" >> "$GITHUB_OUTPUT" build_save-cloud-common: @@ -185,7 +180,6 @@ jobs: 'save-frontend', 'save-orchestrator', 'save-preprocessor', - 'save-sandbox', 'test-analysis-core', 'test-utils' ] @@ -220,8 +214,6 @@ jobs: do-build: ${{ github.event_name == 'push' || needs.calculate_build_flags.outputs.save-orchestrator > 0 }} - module: save-preprocessor do-build: ${{ github.event_name == 'push' || needs.calculate_build_flags.outputs.save-preprocessor > 0 }} - - module: save-sandbox - do-build: ${{ github.event_name == 'push' || needs.calculate_build_flags.outputs.save-sandbox > 0 }} - module: test-analysis-core do-build: ${{ github.event_name == 'push' || needs.calculate_build_flags.outputs.test-analysis-core > 0 }} - module: test-utils diff --git a/.github/workflows/deploy_images.yml b/.github/workflows/deploy_images.yml index b040f12c75..377595cfac 100644 --- a/.github/workflows/deploy_images.yml +++ b/.github/workflows/deploy_images.yml @@ -33,11 +33,6 @@ on: default: true description: Build new image of save-orchestrator required: false - sandbox: - type: boolean - default: true - description: Build new image of save-sandbox - required: false preprocessor: type: boolean default: true @@ -64,7 +59,7 @@ jobs: uses: ./.github/workflows/build_save-agent_reusable.yml with: branch: ${{ inputs.branch }} - build-save-agent: ${{ github.event_name != 'workflow_dispatch' || inputs.backend || inputs.sandbox }} + build-save-agent: ${{ github.event_name != 'workflow_dispatch' || inputs.backend }} build-save-demo-agent: ${{ github.event_name != 'workflow_dispatch' || inputs.demo }} deploy_backend: @@ -77,18 +72,6 @@ jobs: do-build: ${{ github.event_name != 'workflow_dispatch' || inputs.backend }} override-docker-tag: ${{ github.event_name == 'workflow_dispatch' }} save-cli-version: ${{ needs.build_cli.outputs.version }} - - deploy_sandbox: - name: save-sandbox - uses: ./.github/workflows/deploy_images_reusable.yml - needs: [ build_cli, build_agents ] - with: - module: save-sandbox - branch: ${{ inputs.branch }} - do-build: ${{ github.event_name != 'workflow_dispatch' || inputs.sandbox }} - override-docker-tag: ${{ github.event_name == 'workflow_dispatch' }} - save-cli-version: ${{ needs.build_cli.outputs.version }} - deploy_demo: name: save-demo uses: ./.github/workflows/deploy_images_reusable.yml @@ -101,7 +84,7 @@ jobs: save-cli-version: stub deploy_all: - name: all excluding save-backend, save-sandbox and save-demo + name: all excluding save-backend and save-demo strategy: fail-fast: false matrix: diff --git a/.github/workflows/deploy_images_reusable.yml b/.github/workflows/deploy_images_reusable.yml index 5a4844f066..076c2e8a15 100644 --- a/.github/workflows/deploy_images_reusable.yml +++ b/.github/workflows/deploy_images_reusable.yml @@ -75,13 +75,13 @@ jobs: echo SAVE_CLI_GRADLE_OPTS=-PsaveCliVersion=${{ inputs.save-cli-version }} -PsaveCliPath=${{ github.workspace }}/save-cli >> $GITHUB_ENV - name: Download save-agent - if: inputs.module == 'save-backend' || inputs.module == 'save-sandbox' + if: inputs.module == 'save-backend' uses: actions/download-artifact@v3 with: name: save-agent path: ${{ github.workspace }}/save-agent - name: Set saveAgentPath in Gradle - if: inputs.module == 'save-backend' || inputs.module == 'save-sandbox' + if: inputs.module == 'save-backend' run: | echo SAVE_AGENT_GRADLE_OPTS=-PsaveAgentPath=${{ github.workspace }}/save-agent >> $GITHUB_ENV diff --git a/.run/Sandbox-LocalRunOnWindows.run.xml b/.run/Sandbox-LocalRunOnWindows.run.xml deleted file mode 100644 index 48ef6d9518..0000000000 --- a/.run/Sandbox-LocalRunOnWindows.run.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - \ No newline at end of file diff --git a/.run/SaveSandbox-LocalRunOnWindows (ContainerDesktop).run.xml b/.run/SaveSandbox-LocalRunOnWindows (ContainerDesktop).run.xml deleted file mode 100644 index 7e03ceeff7..0000000000 --- a/.run/SaveSandbox-LocalRunOnWindows (ContainerDesktop).run.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ac737cc614..edd010df1c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,11 +20,11 @@ You can enable hot reload by passing `--continuous` flag. ## Spring Intellij Idea Ultimate plugin In order to make Spring Intellij Idea Ultimate plugin work properly, you need to set these active profiles in service's configuration: -| | SaveApplication | SaveGateway | SaveOrchestrator | SavePreprocessor | SaveSandbox | -|:-------:|:----------------:|:-----------:|:--------------------:|:----------------:|:---------------------------:| -| Mac | `mac,dev,secure` | `mac,dev` | `dev,mac,docker-tcp` | `dev,mac` | `dev,mac,docker-tcp,secure` | -| Windows | `dev,secure` | `dev` | `dev,win,docker-tcp` | `dev` | `dev,win,docker-tcp,secure` | -| Linux | `dev,secure` | `dev` | `dev,docker-tcp` | `dev` | `dev,docker-tcp,secure` | +| | SaveApplication | SaveGateway | SaveOrchestrator | SavePreprocessor | +|:-------:|:----------------:|:-----------:|:--------------------:|:----------------:| +| Mac | `mac,dev,secure` | `mac,dev` | `dev,mac,docker-tcp` | `dev,mac` | +| Windows | `dev,secure` | `dev` | `dev,win,docker-tcp` | `dev` | +| Linux | `dev,secure` | `dev` | `dev,docker-tcp` | `dev` | ### Mac M1 contributors In order to run `save-orchestrator` on Mac with M1 in order to make it run executions, in addition to `save-deploy/README.md` you need to diff --git a/api-gateway/README.md b/api-gateway/README.md index 3fe4b83d39..2e7e27224a 100644 --- a/api-gateway/README.md +++ b/api-gateway/README.md @@ -25,7 +25,6 @@ and performs some necessary filtering and header manipulation to ensure proper c The routes are defined based on specific URI paths: - `/sec/**` is not forwarded anywhere but `api-gateway`'s `SecurityInfoController`, which is responsible for `/sec/oauth-providers` endpoint - - `/api/sandbox` is forwarded to `save-sandbox` - `/api/demo` is forwarded to `save-demo` - `/api/cpg` is forwarded to `save-cpg-demo` - `/api/**` is forwarded to `save-backend` diff --git a/api-gateway/src/main/resources/application-dev.yml b/api-gateway/src/main/resources/application-dev.yml index 111161597c..ad621419de 100644 --- a/api-gateway/src/main/resources/application-dev.yml +++ b/api-gateway/src/main/resources/application-dev.yml @@ -4,8 +4,6 @@ gateway: frontend: # In the "dev" environment, the front-end uses TCP port 8080 when run using `webpack-dev-server` (i.e. `browserDevelopmentRun` or `run` Gradle task). url: http://localhost:8080 - sandbox: - url: http://localhost:5400 demo: url: http://localhost:5421 demo-cpg: diff --git a/api-gateway/src/main/resources/application.yml b/api-gateway/src/main/resources/application.yml index 47ad6521a2..c268bf988c 100644 --- a/api-gateway/src/main/resources/application.yml +++ b/api-gateway/src/main/resources/application.yml @@ -7,8 +7,6 @@ gateway: url: http://backend:5800 frontend: url: http://frontend:5810 - sandbox: - url: http://sandbox:5400 demo: url: http://demo:5421 demo-cpg: @@ -27,14 +25,6 @@ spring: cloud: gateway: routes: - - id: sandbox-api_route - uri: ${gateway.sandbox.url} - predicates: - - Path=/api/sandbox/** - filters: - # If SESSION cookie is passed to downstream, it is then removed, because downstream discards it - - RemoveRequestHeader=Cookie - - AuthorizationHeaders= - id: demo-api_route uri: ${gateway.demo.url} predicates: diff --git a/api-gateway/src/test/resources/application-dev.yml b/api-gateway/src/test/resources/application-dev.yml index f1f81a97e4..c749b56c33 100644 --- a/api-gateway/src/test/resources/application-dev.yml +++ b/api-gateway/src/test/resources/application-dev.yml @@ -4,8 +4,6 @@ gateway: frontend: # In the "dev" environment, the front-end uses TCP port 8080 when run using `webpack-dev-server` (i.e. `browserDevelopmentRun` or `run` Gradle task). url: http://localhost:8080 - sandbox: - url: http://localhost:5400 demo: url: http://localhost:5421 demo-cpg: diff --git a/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/config/WebSecurityConfig.kt b/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/config/WebSecurityConfig.kt index f81fce31ef..6d924879c2 100644 --- a/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/config/WebSecurityConfig.kt +++ b/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/config/WebSecurityConfig.kt @@ -97,7 +97,7 @@ class WebSecurityConfig( // they are not proxied from gateway. "/actuator/**", "/internal/**", - // Agents should communicate with sandbox without authorization + // Agents should communicate without authorization "/heartbeat", // `CollectionView` is a public page "/api/$v1/projects/by-filters", diff --git a/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DatabaseUtils.kt b/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DatabaseUtils.kt index f2ec0089c5..a7e434bc68 100644 --- a/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DatabaseUtils.kt +++ b/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DatabaseUtils.kt @@ -23,7 +23,7 @@ data class DatabaseCredentials( } /** - * @param projectName save-backend, save-sandbox or save-demo + * @param projectName save-backend or save-demo * @param profile a profile to get credentials for * @return an instance of [DatabaseCredentials] for [profile] in [projectName] */ diff --git a/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DockerStackConfiguration.kt b/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DockerStackConfiguration.kt index d303d3eda7..1e9d7832f3 100644 --- a/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DockerStackConfiguration.kt +++ b/buildSrc/src/main/kotlin/com/saveourtool/save/buildutils/DockerStackConfiguration.kt @@ -30,11 +30,7 @@ fun Project.registerLiquibaseTask(profile: String) { relativeChangeLogFile = "db/db.changelog-master.xml", profile = profile ) - val registerLiquibaseTaskSandbox = registerLiquibaseTask( - projectName = "save-sandbox", - relativeChangeLogFile = "save-sandbox/db/db.changelog-sandbox.xml", - profile = profile - ) + val registerLiquibaseTaskDemo = registerLiquibaseTask( projectName = "save-demo", relativeChangeLogFile = "save-demo/db/db.changelog-demo.xml", @@ -48,7 +44,6 @@ fun Project.registerLiquibaseTask(profile: String) { tasks.register("liquibaseUpdate") { dependsOn( registerLiquibaseTaskBackend, - registerLiquibaseTaskSandbox, registerLiquibaseTaskDemo, registerLiquibaseTaskCosv, ) @@ -211,7 +206,6 @@ fun Project.createStackDeployTask(profile: String) { FRONTEND_TAG=${defaultVersionOrProperty("frontend.dockerTag")} GATEWAY_TAG=${defaultVersionOrProperty("gateway.dockerTag")} ORCHESTRATOR_TAG=${defaultVersionOrProperty("orchestrator.dockerTag")} - SANDBOX_TAG=${defaultVersionOrProperty("sandbox.dockerTag")} PREPROCESSOR_TAG=${defaultVersionOrProperty("preprocessor.dockerTag")} DEMO_TAG=${defaultVersionOrProperty("demo.dockerTag")} PROFILE=$profile @@ -248,7 +242,6 @@ fun Project.createStackDeployTask(profile: String) { Files.createDirectories(configsDir.resolve("backend")) Files.createDirectories(configsDir.resolve("gateway")) Files.createDirectories(configsDir.resolve("orchestrator")) - Files.createDirectories(configsDir.resolve("sandbox")) Files.createDirectories(configsDir.resolve("preprocessor")) Files.createDirectories(configsDir.resolve("demo")) } @@ -331,7 +324,6 @@ fun Project.createStackDeployTask(profile: String) { "up", "-d", "orchestrator", - "sandbox", "backend", "frontend", "preprocessor", @@ -351,7 +343,7 @@ fun Project.createStackDeployTask(profile: String) { project(componentName).tasks.named("bootBuildImage") dependsOn(buildTask) val serviceName = when (componentName) { - "save-backend", "save-frontend", "save-orchestrator", "save-sandbox", "save-preprocessor" -> "save_${componentName.substringAfter("save-")}" + "save-backend", "save-frontend", "save-orchestrator", "save-preprocessor" -> "save_${componentName.substringAfter("save-")}" "api-gateway" -> "save_gateway" else -> error("Wrong component name $componentName") } diff --git a/docker-compose.yaml b/docker-compose.yaml index c3fd867f84..b7457743dc 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -33,26 +33,6 @@ services: labels: - "prometheus-job=save-orchestrator" logging: *loki-logging-jvm - sandbox: - image: ghcr.io/saveourtool/save-sandbox:${SANDBOX_TAG} - user: root # to access host's docker socket - environment: - - "SPRING_PROFILES_ACTIVE=${PROFILE},secure,docker-secrets" - secrets: - - db_username - - db_password - ports: - - "5400:5400" - volumes: - - "/var/run/docker.sock:/var/run/docker.sock" - - /home/saveu/configs/sandbox:/home/cnb/config - - save-tmp-resources:/tmp - extra_hosts: - - "host.docker.internal:host-gateway" - deploy: - labels: - - "prometheus-job=save-sandbox" - logging: *loki-logging-jvm backend: image: ghcr.io/saveourtool/save-backend:${BACKEND_TAG} environment: diff --git a/gradle/plugins/src/main/kotlin/com/saveourtool/save/buildutils/spring-boot-app-configuration.gradle.kts b/gradle/plugins/src/main/kotlin/com/saveourtool/save/buildutils/spring-boot-app-configuration.gradle.kts index dd8656b355..8569d9f873 100644 --- a/gradle/plugins/src/main/kotlin/com/saveourtool/save/buildutils/spring-boot-app-configuration.gradle.kts +++ b/gradle/plugins/src/main/kotlin/com/saveourtool/save/buildutils/spring-boot-app-configuration.gradle.kts @@ -33,7 +33,7 @@ tasks.withType().configureEach { os.isWindows -> append(",win") os.isMacOsX -> append(",mac") } - if (listOf("save-sandbox", "save-backend", "save-cosv").any { project.path.contains(it) }) { + if (listOf("save-backend", "save-cosv").any { project.path.contains(it) }) { append(",secure") } } diff --git a/save-cloud-charts/save-cloud/README.md b/save-cloud-charts/save-cloud/README.md index 0dc0a52bb4..c1d71d8cae 100644 --- a/save-cloud-charts/save-cloud/README.md +++ b/save-cloud-charts/save-cloud/README.md @@ -10,7 +10,6 @@ api-gateway acts as an entrypoint and svc/gateway is actually a LoadBalancer. * `spring.datasource.username` * `spring.datasource.password` * `spring.datasource.backend-url` - * `spring.datasource.sandbox-url` * `spring.datasource.demo-url` These secrets are then mounted under the path specified as `DATABASE_SECRETS_PATH` environment variable. @@ -75,6 +74,6 @@ command line using `--set` flag. $ helm --kube-context=minikube --namespace=save-cloud upgrade -i save-cloud save-cloud-0.1.0.tgz/ --values values-minikube.yaml --values=values-images.yaml ``` * Database migrations can be run by setting value `mysql.migrations.enabled` to `true` (no additional setup, migrations - are executed by init container, but may be too slow with constant recreations of backend/sandbox pods) + are executed by init container, but may be too slow with constant recreations of backend pods) or port 3306 of mysql pod can be forwarded and `liquibaseUpdate` can be executed manually. If needed, don't forget that JDBC URL for liquibase in dev profile is read from `application-dev.properties` value `dev.datasource.url`. diff --git a/save-cloud-charts/save-cloud/templates/agent-network-policy-orchestrator.yaml b/save-cloud-charts/save-cloud/templates/agent-network-policy-orchestrator.yaml index f92dba1a16..c01ab713d0 100644 --- a/save-cloud-charts/save-cloud/templates/agent-network-policy-orchestrator.yaml +++ b/save-cloud-charts/save-cloud/templates/agent-network-policy-orchestrator.yaml @@ -6,8 +6,7 @@ metadata: spec: # Should be applied to save-agents only # - # As for now, there is no way to tell orchestrator pod from sandbox pod so need to allow connection to both - # orchestrator and sandbox. + # As for now, there is no way to tell orchestrator pod so need to allow connection to orchestrator. podSelector: matchLabels: io.kompose.service: save-agent @@ -36,14 +35,3 @@ spec: ports: - protocol: TCP port: {{ .Values.backend.containerPort }} - - to: - # Allow traffic to save-sandbox - - namespaceSelector: - matchLabels: - name: {{ .Values.namespace }} - - podSelector: - matchLabels: - io.kompose.service: sandbox - ports: - - protocol: TCP - port: {{ .Values.sandbox.containerPort }} \ No newline at end of file diff --git a/save-cloud-charts/save-cloud/templates/agent-sandbox-service.yaml b/save-cloud-charts/save-cloud/templates/agent-sandbox-service.yaml deleted file mode 100644 index 8cb2441a77..0000000000 --- a/save-cloud-charts/save-cloud/templates/agent-sandbox-service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -{{ if .Values.agentNamespace }} - -apiVersion: v1 -kind: Service -metadata: - name: {{ .Values.sandbox.name }} - namespace: {{ .Values.agentNamespace }} -spec: - type: ExternalName - externalName: {{ .Values.sandbox.name }}.{{ .Values.namespace }}.svc.cluster.local - ports: - - port: {{ .Values.sandbox.containerPort }} - -{{ end }} diff --git a/save-cloud-charts/save-cloud/templates/gateway-configmap.yaml b/save-cloud-charts/save-cloud/templates/gateway-configmap.yaml index 8cdad682bf..68a3c773c1 100644 --- a/save-cloud-charts/save-cloud/templates/gateway-configmap.yaml +++ b/save-cloud-charts/save-cloud/templates/gateway-configmap.yaml @@ -6,7 +6,6 @@ data: application.properties: | gateway.backend.url=http://backend gateway.frontend.url=http://frontend - gateway.sandbox.url=http://sandbox gateway.demo-cpg.url=http://demo-cpg gateway.demo.url=http://demo server.shutdown=graceful diff --git a/save-cloud-charts/save-cloud/templates/mysql-deployment.yaml b/save-cloud-charts/save-cloud/templates/mysql-deployment.yaml index 5b829410f1..6b604a7191 100644 --- a/save-cloud-charts/save-cloud/templates/mysql-deployment.yaml +++ b/save-cloud-charts/save-cloud/templates/mysql-deployment.yaml @@ -7,7 +7,6 @@ metadata: name: db-secrets stringData: spring.datasource.backend-url: 'jdbc:mysql://mysql-service:3306/{{ .Values.mysql.backend_schema }}' - spring.datasource.sandbox-url: 'jdbc:mysql://mysql-service:3306/{{ .Values.mysql.sandbox_schema }}' spring.datasource.demo-url: 'jdbc:mysql://mysql-service:3306/{{ .Values.mysql.demo_schema }}' spring.datasource.username: root spring.datasource.password: {{ .Values.mysql.root_password | quote }} diff --git a/save-cloud-charts/save-cloud/templates/sandbox-configmap.yaml b/save-cloud-charts/save-cloud/templates/sandbox-configmap.yaml deleted file mode 100644 index 3a304a1c94..0000000000 --- a/save-cloud-charts/save-cloud/templates/sandbox-configmap.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ .Values.sandbox.name }}-config -data: - application.properties: | - orchestrator.kubernetes.apiServerUrl=http://kubernetes.default.svc - orchestrator.kubernetes.serviceAccount=${POD_SERVICE_ACCOUNT} - orchestrator.kubernetes.current-namespace=${POD_NAMESPACE} - orchestrator.kubernetes.agent-namespace= {{ .Values.agentNamespace }} - - server.shutdown=graceful - management.endpoints.web.exposure.include=* - management.server.port={{ .Values.sandbox.managementPort }} - spring.datasource.url=${spring.datasource.sandbox-url} - - sandbox.agent-settings.sandbox-url=http://{{ .Values.sandbox.name }} - orchestrator.agent-settings.heartbeat-url=http://{{ .Values.sandbox.name }}/heartbeat - orchestrator.agent-settings.debug=true - - logging.level.com.saveourtool.save.orchestrator.kubernetes=DEBUG - - {{ if .Values.sandbox.applicationProperties }} - {{- .Values.sandbox.applicationProperties | nindent 4 }} - {{ end }} \ No newline at end of file diff --git a/save-cloud-charts/save-cloud/templates/sandbox-deployment.yaml b/save-cloud-charts/save-cloud/templates/sandbox-deployment.yaml deleted file mode 100644 index 0502bcfb55..0000000000 --- a/save-cloud-charts/save-cloud/templates/sandbox-deployment.yaml +++ /dev/null @@ -1,152 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: sandbox - labels: - {{- include "common.labels" (merge (dict "service" .Values.sandbox) .) | nindent 4 }} -spec: - selector: - matchLabels: - io.kompose.service: sandbox - replicas: 1 - strategy: - # Because of shared volume with multi-attach problem - type: Recreate - template: - metadata: - labels: - {{- include "pod.common.labels" (merge (dict "service" .Values.sandbox ) .) | nindent 8 }} - annotations: - {{- include "pod.common.annotations" (dict "service" .Values.backend ) | nindent 8 }} - spec: - serviceAccountName: sandbox-sa - restartPolicy: Always - {{- if .Values.sandbox.nodeName }} - nodeName: {{ .Values.sandbox.nodeName }} - {{- end }} - {{- include "cnb.securityContext" . | nindent 6 }} - containers: - - name: sandbox - {{- include "spring-boot.common" (merge (dict "service" .Values.sandbox) .) | nindent 10 }} - env: - {{- include "spring-boot.common.env" (merge (dict "service" .Values.sandbox) .) | nindent 12 }} - - name: HOST_IP - valueFrom: - fieldRef: - fieldPath: status.hostIP - - name: DATABASE_SECRETS_PATH - value: {{ .Values.mysql.dbPasswordFile }} - - name: S3_SECRETS_PATH - value: {{ .Values.s3.secretFile }} - - name: JAVA_TOOL_OPTIONS - value: -XX:ReservedCodeCacheSize=48M - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: POD_SERVICE_ACCOUNT - valueFrom: - fieldRef: - fieldPath: spec.serviceAccountName - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - volumeMounts: - - {{ include "spring-boot.config-volume-mount" . | indent 14 | trim }} - - name: database-secret - mountPath: {{ .Values.mysql.dbPasswordFile }} - - name: s3-secrets - mountPath: {{ .Values.s3.secretFile }} - {{- include "spring-boot.management" .Values.sandbox | nindent 10 }} - resources: - limits: - memory: 800M - requests: - memory: 600M - {{ if .Values.mysql.migrations.enabled }} - initContainers: - - name: git-cloner - image: alpine/git - env: - {{ if .Values.proxy.enabled }} - {{- with .Values.proxy.extraEnv }} - {{- toYaml . | nindent 12 }} - {{- end }} - {{ end }} - args: - - clone - - --progress - - --verbose - {{ if .Values.proxy.enabled }} - {{- with .Values.proxy.extraArgs }} - {{- toYaml . | nindent 12 }} - {{- end }} - {{ end }} - - --single-branch - - --branch - - {{ .Values.mysql.migrations.branch | default "master" }} - - -- - - https://github.com/saveourtool/save-cloud.git - - /data - volumeMounts: - - mountPath: /data - name: migrations-data - - name: liquibase-runner - image: liquibase/liquibase:4.20 - securityContext: - runAsUser: 1001 - runAsGroup: 1001 - args: - - --url=$(DB_URL)?createDatabaseIfNotExist=true - - --changeLogFile=save-sandbox/db/db.changelog-sandbox.xml - - --username=$(DB_USERNAME) - - --password=$(DB_PASSWORD) - - --log-level=info - - --contexts={{ .Values.profile }} - - update - resources: - requests: - memory: 100M - limits: - memory: 300M - env: - # See https://hub.docker.com/r/liquibase/liquibase, section 'Notice for MySQL Users' - - name: INSTALL_MYSQL - value: 'true' - - name: DB_URL - valueFrom: - secretKeyRef: - name: db-secrets - key: spring.datasource.sandbox-url - - name: DB_USERNAME - valueFrom: - secretKeyRef: - name: db-secrets - key: spring.datasource.username - - name: DB_PASSWORD - valueFrom: - secretKeyRef: - name: db-secrets - key: spring.datasource.password - {{ if .Values.proxy.enabled }} - {{- with .Values.proxy.extraEnv }} - {{- toYaml . | nindent 12 }} - {{- end }} - {{ end }} - volumeMounts: - - mountPath: /liquibase/changelog - name: migrations-data - - mountPath: {{ .Values.mysql.dbPasswordFile }} - name: database-secret - {{ end }} - volumes: - - {{ include "spring-boot.config-volume" (dict "service" .Values.sandbox) | indent 10 | trim }} - - name: database-secret - secret: - secretName: db-secrets - - name: s3-secrets - secret: - secretName: s3-secrets - - name: migrations-data - emptyDir: { } diff --git a/save-cloud-charts/save-cloud/templates/sandbox-service-account.yaml b/save-cloud-charts/save-cloud/templates/sandbox-service-account.yaml deleted file mode 100644 index c7ad887be0..0000000000 --- a/save-cloud-charts/save-cloud/templates/sandbox-service-account.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: sandbox-sa - ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: sandbox-jobs-binding - {{ if .Values.agentNamespace }} - namespace: {{ .Values.agentNamespace }} - {{ end }} -subjects: - - kind: ServiceAccount - name: sandbox-sa - namespace: {{ .Values.namespace }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: jobs-executor diff --git a/save-cloud-charts/save-cloud/templates/sandbox-service.yaml b/save-cloud-charts/save-cloud/templates/sandbox-service.yaml deleted file mode 100644 index a2cdb9e7f6..0000000000 --- a/save-cloud-charts/save-cloud/templates/sandbox-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: -{{- include "service.common.metadata" (dict "service" .Values.sandbox) | nindent 2 }} -spec: - {{ if .Values.sandbox.clusterIP }} - clusterIP: {{ .Values.sandbox.clusterIP }} - {{ end }} - ports: - {{- include "service.common.ports" (dict "service" .Values.sandbox) | nindent 4 }} - selector: - {{- include "service.common.selectors" (dict "service" .Values.sandbox) | nindent 4 }} diff --git a/save-cloud-charts/save-cloud/values-images.yaml b/save-cloud-charts/save-cloud/values-images.yaml index e7c1283710..1c729aa564 100644 --- a/save-cloud-charts/save-cloud/values-images.yaml +++ b/save-cloud-charts/save-cloud/values-images.yaml @@ -17,8 +17,6 @@ preprocessor: dockerTag: '0.4.0-alpha.0.379-70423bd' orchestrator: dockerTag: '0.4.0-alpha.0.379-70423bd' -sandbox: - dockerTag: '0.4.0-alpha.0.379-70423bd' demo: dockerTag: '0.4.0-alpha.0.379-70423bd' demo_cpg: diff --git a/save-cloud-charts/save-cloud/values-minikube.yaml b/save-cloud-charts/save-cloud/values-minikube.yaml index 2fc3bf2587..bbd5e41648 100644 --- a/save-cloud-charts/save-cloud/values-minikube.yaml +++ b/save-cloud-charts/save-cloud/values-minikube.yaml @@ -18,13 +18,6 @@ orchestrator: orchestrator.agents-count=1 logging.level.com.saveourtool=DEBUG orchestrator.kubernetes.useGvisor=false -sandbox: - profile: dev,kubernetes,minikube - dockerHost: tcp://${HOST_IP}:2376 - applicationProperties: | - orchestrator.docker.host=tcp://localhost:2376 - logging.level.com.saveourtool=DEBUG - orchestrator.kubernetes.useGvisor=false demo_cpg: profile: dev demo: diff --git a/save-cloud-charts/save-cloud/values.yaml b/save-cloud-charts/save-cloud/values.yaml index 9983321f80..bf1830bb90 100644 --- a/save-cloud-charts/save-cloud/values.yaml +++ b/save-cloud-charts/save-cloud/values.yaml @@ -30,15 +30,6 @@ orchestrator: # Fixed ClusterIP can be assigned to make it easier to query orchestrator from services outside Kubernetes clusterIP: null dockerHost: tcp://${HOST_IP}:2375 -sandbox: - name: sandbox - profile: dev,secure - imageName: save-sandbox - containerPort: 5400 - managementPort: 5401 - # Fixed ClusterIP can be assigned to make it easier to query orchestrator from services outside Kubernetes - clusterIP: null - dockerHost: tcp://${HOST_IP}:2375 preprocessor: name: preprocessor imageName: save-preprocessor @@ -78,7 +69,6 @@ mysql: ip: 192.168.65.2 # Name of the database schema that will be used by save-cloud deployment backend_schema: save_cloud - sandbox_schema: save_sandbox demo_schema: save_demo cosv_schema: cosv root_password: '123' diff --git a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/domain/SandboxFileInfo.kt b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/domain/SandboxFileInfo.kt deleted file mode 100644 index f6a28e6d11..0000000000 --- a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/domain/SandboxFileInfo.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.saveourtool.save.domain - -import kotlinx.serialization.Serializable - -/** - * Class that contains metadata of Sandbox files - * - * @property sizeBytes size in bytes - * @property name name of a file - */ -@Serializable -data class SandboxFileInfo( - val name: String, - val sizeBytes: Long, -) diff --git a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/validation/FrontendRoutes.kt b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/validation/FrontendRoutes.kt index c427a6b502..f34758f3ca 100644 --- a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/validation/FrontendRoutes.kt +++ b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/validation/FrontendRoutes.kt @@ -33,7 +33,6 @@ enum class FrontendRoutes(val path: String) { PROFILE("profile"), PROJECTS("projects"), REGISTRATION("registration"), - SANDBOX("sandbox"), SAVE("save"), SETTINGS_DELETE("$SETTINGS/delete"), SETTINGS_EMAIL("$SETTINGS/email"), diff --git a/save-deploy/README.md b/save-deploy/README.md index 5fac7eaaa6..4eee066d87 100644 --- a/save-deploy/README.md +++ b/save-deploy/README.md @@ -18,12 +18,12 @@ Deployment is performed on server via docker swarm or locally via `docker compos The `libs.version.toml` contains `save-cli` version. The `save-agent` uses this version as a compile dependency to read execution's reports. -The `save-backend` and `save-sandbox` download newer versions of `save-cli` from _GitHub_ on startup. +The `save-backend` downloads newer versions of `save-cli` from _GitHub_ on startup. #### Using a `SNAPSHOT` version of `save-cli` If `save-cli` is set to snapshot version in `lib.version.toml`, we download `save-cli`'s sources and build them in _GitHub_ action: [Build and push Docker images](../.github/workflows/deploy_images.yml). -Then _Gradle_ adds the result (_.kexe_) to `save-backend` and `save-sandbox` as a runtime dependency +Then _Gradle_ adds the result (_.kexe_) to `save-backend` as a runtime dependency **Under the hood:** _Gradle_ supports two variables `saveCliVersion` and `saveCliPath`. The `saveCliVersion` overrides version of `save-cli` from `lib.version.toml`. @@ -283,7 +283,6 @@ Do not forget to use `mac` profile. | 5100 | save-orchestrator | | 5200 | save-test-preprocessor | | 5300 | api-gateway | -| 5400 | save-sandbox | | 9090 | prometheus | | 9091 | node_exporter | | 9100 | grafana | diff --git a/save-frontend-common/README.md b/save-frontend-common/README.md index 906098999c..2b58f82104 100644 --- a/save-frontend-common/README.md +++ b/save-frontend-common/README.md @@ -53,17 +53,6 @@ config.devServer = Object.assign( return middlewares; }, proxy: [ - { - context: ["/api/sandbox/**"], - target: 'http://localhost:5400', - logLevel: 'debug', - onProxyReq: function (proxyReq, req, res) { - proxyReq.setHeader("X-Authorization-Id", "1"); - proxyReq.setHeader("X-Authorization-Name", "admin"); - proxyReq.setHeader("X-Authorization-Roles", "ROLE_SUPER_ADMIN"); - proxyReq.setHeader("X-Authorization-Status", "ACTIVE"); - } - }, { context: ["/api/demo/**"], target: 'http://localhost:5421', diff --git a/save-frontend/README.md b/save-frontend/README.md index 90ac2ec60c..786c923e1f 100644 --- a/save-frontend/README.md +++ b/save-frontend/README.md @@ -62,17 +62,6 @@ config.devServer = Object.assign( return middlewares; }, proxy: [ - { - context: ["/api/sandbox/**"], - target: 'http://localhost:5400', - logLevel: 'debug', - onProxyReq: function (proxyReq, req, res) { - proxyReq.setHeader("X-Authorization-Id", "1"); - proxyReq.setHeader("X-Authorization-Name", "admin"); - proxyReq.setHeader("X-Authorization-Roles", "ROLE_SUPER_ADMIN"); - proxyReq.setHeader("X-Authorization-Status", "ACTIVE"); - } - }, { context: ["/api/demo/**"], target: 'http://localhost:5421', diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/codeeditor/SandboxCodeEditorComponent.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/codeeditor/SandboxCodeEditorComponent.kt deleted file mode 100644 index 7d942cc73d..0000000000 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/codeeditor/SandboxCodeEditorComponent.kt +++ /dev/null @@ -1,187 +0,0 @@ -@file:Suppress("FILE_NAME_MATCH_CLASS", "HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE") - -package com.saveourtool.save.frontend.components.basic.codeeditor - -import com.saveourtool.save.frontend.common.utils.* -import com.saveourtool.save.frontend.common.utils.WithRequestStatusContext -import com.saveourtool.save.frontend.components.basic.codeeditor.FileType.Companion.getTypedOption -import com.saveourtool.save.frontend.components.basic.codeeditor.FileType.SAVE_TOML -import com.saveourtool.save.frontend.components.basic.codeeditor.FileType.SETUP_SH -import com.saveourtool.save.frontend.components.basic.codeeditor.FileType.TEST -import com.saveourtool.save.frontend.components.views.sandboxApiUrl -import com.saveourtool.save.frontend.externals.reactace.AceThemes -import com.saveourtool.save.utils.Languages - -import react.FC -import react.Props -import react.dom.html.ReactHTML.div -import react.dom.html.ReactHTML.h6 -import react.useState -import web.cssom.ClassName - -import kotlinx.browser.window -import kotlinx.coroutines.await - -private const val DEFAULT_EDITOR_MESSAGE = "Select one of the files above to start editing it!" - -private const val TEXT_PLACEHOLDER = "Please load data from server using button above." - -/** - * CodeEditor component for sandbox that encapsulates toolbar and oen editor for three different files. - */ -val sandboxCodeEditorComponent = sandboxCodeEditorComponent() - -/** - * SandboxCodeEditor functional component [Props] - */ -external interface SandboxCodeEditorComponentProps : Props { - /** - * Title of an editor - */ - var editorTitle: String? - - /** - * Action to run execution - */ - var doRunExecution: () -> Unit - - /** - * Action to reload debug info - */ - var doResultReload: () -> Unit -} - -private suspend fun WithRequestStatusContext.postTextRequest( - urlPart: String, - content: String, - fileName: String, -) = post( - url = "$sandboxApiUrl/upload-$urlPart-as-text?fileName=$fileName", - headers = jsonHeaders, - body = content, - loadingHandler = ::noopLoadingHandler, -).ok - -private suspend fun WithRequestStatusContext.getTextRequest( - urlPart: String, - fileName: String, -) = get( - url = "$sandboxApiUrl/download-$urlPart-as-text?fileName=$fileName", - headers = jsonHeaders, - loadingHandler = ::noopLoadingHandler, -) - .let { response -> - if (response.ok) { - response.text().await() - } else { - null - } - } - -@Suppress("TOO_LONG_FUNCTION", "LongMethod", "ComplexMethod") -private fun sandboxCodeEditorComponent() = FC { props -> - val (selectedMode, setSelectedMode) = useState(Languages.KOTLIN) - val (selectedTheme, setSelectedTheme) = useState(AceThemes.CHROME) - val (selectedFileType, setSelectedFileType) = useState(null) - - val (draftCodeText, setDraftCodeText) = useState(TEXT_PLACEHOLDER) - val (draftConfigText, setDraftConfigText) = useState(TEXT_PLACEHOLDER) - val (draftSetupShText, setDraftSetupShText) = useState(TEXT_PLACEHOLDER) - - val (savedCodeText, setSavedCodeText) = useState(TEXT_PLACEHOLDER) - val (savedConfigText, setSavedConfigText) = useState(TEXT_PLACEHOLDER) - val (savedSetupShText, setSavedSetupShText) = useState(TEXT_PLACEHOLDER) - - val fetchTexts = useDeferredRequest { - FileType.values().forEach { fileType -> - val text = getTextRequest(fileType.urlPart, fileType.fileName) ?: TEXT_PLACEHOLDER - getTypedOption(fileType, setSavedCodeText, setSavedConfigText, setSavedSetupShText)(text) - getTypedOption(fileType, setDraftCodeText, setDraftConfigText, setDraftSetupShText)(text) - } - } - - val fetchText = useDeferredRequest { - selectedFileType?.let { fileType -> - val text = getTextRequest(fileType.urlPart, fileType.fileName) ?: TEXT_PLACEHOLDER - getTypedOption(fileType, setSavedCodeText, setSavedConfigText, setSavedSetupShText)(text) - getTypedOption(fileType, setDraftCodeText, setDraftConfigText, setDraftSetupShText)(text) - } - } - - val uploadText = useDeferredRequest { - selectedFileType?.let { fileType -> - val content = getTypedOption(fileType, draftCodeText, draftConfigText, draftSetupShText) - if (postTextRequest(fileType.urlPart, content, fileType.fileName)) { - getTypedOption(fileType, setSavedCodeText, setSavedConfigText, setSavedSetupShText)(content) - } - } - } - - val uploadTexts = useDeferredRequest { - FileType.values().forEach { fileType -> - val content = getTypedOption(fileType, draftCodeText, draftConfigText, draftSetupShText) - if (postTextRequest(fileType.urlPart, content, fileType.fileName)) { - getTypedOption(fileType, setSavedCodeText, setSavedConfigText, setSavedSetupShText)(content) - } - } - } - - useOnce(fetchTexts) - - div { - props.editorTitle?.let { editorTitle -> - h6 { - className = ClassName("text-center text-primary") - +editorTitle - } - } - val hasUncommittedChanges = mapOf( - TEST to (savedCodeText != draftCodeText), - SAVE_TOML to (savedConfigText != draftConfigText), - SETUP_SH to (savedSetupShText != draftSetupShText), - ) - displayCodeEditorToolbar( - selectedMode, - selectedTheme, - selectedFileType, - hasUncommittedChanges, - { newModeName -> setSelectedMode(Languages.values().find { it.modeName == newModeName }!!) }, - { newThemeName -> setSelectedTheme(AceThemes.values().find { it.themeName == newThemeName }!!) }, - onUploadChanges = uploadText, - onReloadChanges = fetchText, - onResultReload = props.doResultReload, - onRunExecution = { - val hasAnyUncommittedChanges = hasUncommittedChanges.any { (_, hasChanges) -> - hasChanges - } - if (hasAnyUncommittedChanges) { - if (window.confirm("Some changes are not saved. Save and run execution?")) { - uploadTexts() - props.doRunExecution() - } else { - window.alert("Run canceled.") - } - } else { - uploadTexts() - props.doRunExecution() - } - }, - ) { fileType -> - if (fileType == selectedFileType) { - setSelectedFileType(null) - } else { - setSelectedFileType(fileType) - } - } - - codeEditorComponent { - editorTitle = props.editorTitle - isDisabled = selectedFileType == null - this.selectedTheme = selectedTheme - this.selectedMode = selectedMode - onDraftTextUpdate = { text -> getTypedOption(selectedFileType, setDraftCodeText, setDraftConfigText, setDraftSetupShText)?.invoke(text) } - savedText = getTypedOption(selectedFileType, savedCodeText, savedConfigText, savedSetupShText) ?: DEFAULT_EDITOR_MESSAGE - draftText = getTypedOption(selectedFileType, draftCodeText, draftConfigText, draftSetupShText) ?: DEFAULT_EDITOR_MESSAGE - } - } -} diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/fileuploader/SandboxFileUploader.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/fileuploader/SandboxFileUploader.kt deleted file mode 100644 index b37b2ff9a6..0000000000 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/fileuploader/SandboxFileUploader.kt +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Component for uploading files - */ - -@file:Suppress("FILE_NAME_MATCH_CLASS") - -package com.saveourtool.save.frontend.components.basic.fileuploader - -import com.saveourtool.save.domain.* -import com.saveourtool.save.frontend.common.components.basic.fileuploader.deleteFileButton -import com.saveourtool.save.frontend.common.components.basic.fileuploader.downloadFileButton -import com.saveourtool.save.frontend.common.components.inputform.dragAndDropForm -import com.saveourtool.save.frontend.common.http.postUploadFile -import com.saveourtool.save.frontend.common.utils.* -import com.saveourtool.save.frontend.common.utils.noopLoadingHandler -import com.saveourtool.save.frontend.components.basic.codeeditor.FileType - -import js.core.asList -import react.* -import react.dom.html.ReactHTML.div -import react.dom.html.ReactHTML.li -import react.dom.html.ReactHTML.ul -import web.cssom.ClassName -import web.file.File - -import kotlinx.browser.window - -/** - * [FC] for sandbox file uploading - */ -@Suppress( - "TOO_LONG_FUNCTION", - "TYPE_ALIAS", - "LongMethod", - "ComplexMethod", -) -val sandboxFileUploader: FC = FC { props -> - val (selectedFiles, setSelectedFiles) = useState>(emptyList()) - - useRequest { - val listOfFileInfos: List = get( - props.getUrlForAvailableFilesFetch(), - jsonHeaders, - loadingHandler = ::noopLoadingHandler, - ).decodeFromJsonString() - setSelectedFiles { it + listOfFileInfos } - } - - val (fileToDelete, setFileToDelete) = useState(null) - val deleteFile = useDeferredRequest { - fileToDelete?.let { - val response = delete( - props.getUrlForFileDeletion(fileToDelete), - jsonHeaders, - loadingHandler = ::loadingHandler, - ) - - if (response.ok) { - setSelectedFiles { it - fileToDelete } - setFileToDelete(null) - } - } - } - - val (filesForUploading, setFilesForUploading) = useState>(emptyList()) - val uploadFiles = useDeferredRequest { - filesForUploading.forEach { fileForUploading -> - if (fileForUploading.name != FileType.SETUP_SH.fileName) { - val uploadedFileInfo: SandboxFileInfo = postUploadFile( - url = props.getUrlForFileUpload(), - file = fileForUploading, - loadingHandler = ::loadingHandler, - ) - .decodeFromJsonString() - setSelectedFiles { it + uploadedFileInfo } - } else { - window.alert("Use code editor instead of file uploader to manage ${fileForUploading.name}, please.") - } - } - } - - div { - ul { - className = ClassName("list-group") - - // ===== SELECTED FILES ===== - selectedFiles - .filter { it.name != FileType.SETUP_SH.fileName } - .map { file -> - li { - className = ClassName("list-group-item") - downloadFileButton(file, SandboxFileInfo::name, props.getUrlForFileDownload) - deleteFileButton(file, SandboxFileInfo::name) { - setFileToDelete(it) - deleteFile() - } - +file.name - } - } - - // ===== UPLOAD FILES BUTTON ===== - li { - className = ClassName("list-group-item p-0 d-flex bg-light") - dragAndDropForm { - isDisabled = false - isMultipleFilesSupported = false - tooltipMessage = "upload your tested tool and all other needed files" - onChangeEventHandler = { files -> - setFilesForUploading(files!!.asList()) - uploadFiles() - } - } - } - } - } - useTooltip() -} - -/** - * Props for file uploader - */ -external interface SandboxFileUploaderProps : Props { - /** - * Url for fetching existing in storage files - */ - var getUrlForAvailableFilesFetch: () -> String - - /** - * Callback to get url for file uploading to storage - */ - var getUrlForFileUpload: () -> String - - /** - * Callback to get url for file downloading from storage - */ - var getUrlForFileDownload: (SandboxFileInfo) -> String - - /** - * Callback to get url for file deletion from storage - */ - var getUrlForFileDeletion: (SandboxFileInfo) -> String -} diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/topbar/TopBarLinks.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/topbar/TopBarLinks.kt index 81981a8edc..a516f97106 100644 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/topbar/TopBarLinks.kt +++ b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/topbar/TopBarLinks.kt @@ -31,7 +31,6 @@ val topBarLinks: FC = FC { props -> TopBarLink(hrefAnchor = FrontendRoutes.DEMO.path, text = "Demo".t()), TopBarLink(hrefAnchor = "${FrontendRoutes.DEMO}/cpg", text = "CPG".t()), TopBarLink(hrefAnchor = FrontendRoutes.AWESOME_BENCHMARKS.path, text = "Awesome Benchmarks".t()), - TopBarLink(hrefAnchor = FrontendRoutes.SANDBOX.path, text = "Try SAVE format".t()), TopBarLink(hrefAnchor = FrontendRoutes.PROJECTS.path, text = "Projects board".t()), TopBarLink(hrefAnchor = FrontendRoutes.CONTESTS.path, text = "Contests".t()), TopBarLink(hrefAnchor = FrontendRoutes.ABOUT_US.path, text = "About us".t()), diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/SandboxView.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/SandboxView.kt deleted file mode 100644 index 505f070cbf..0000000000 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/SandboxView.kt +++ /dev/null @@ -1,169 +0,0 @@ -@file:Suppress("HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE") - -package com.saveourtool.save.frontend.components.views - -import com.saveourtool.save.core.result.Crash -import com.saveourtool.save.core.result.Fail -import com.saveourtool.save.core.result.Ignored -import com.saveourtool.save.core.result.Pass -import com.saveourtool.save.domain.Sdk -import com.saveourtool.save.domain.TestResultDebugInfo -import com.saveourtool.save.frontend.common.components.modal.displayModal -import com.saveourtool.save.frontend.common.components.modal.largeTransparentModalStyle -import com.saveourtool.save.frontend.common.externals.fontawesome.faTimesCircle -import com.saveourtool.save.frontend.common.externals.fontawesome.fontAwesomeIcon -import com.saveourtool.save.frontend.common.utils.* -import com.saveourtool.save.frontend.common.utils.get -import com.saveourtool.save.frontend.components.basic.codeeditor.sandboxCodeEditorComponent -import com.saveourtool.save.frontend.components.basic.fileuploader.sandboxFileUploader -import com.saveourtool.save.frontend.components.basic.sdkSelection - -import io.ktor.http.* -import js.core.jso -import org.w3c.fetch.Headers -import react.* -import react.dom.aria.AriaRole -import react.dom.aria.ariaLabel -import react.dom.html.ReactHTML.button -import react.dom.html.ReactHTML.div -import react.dom.html.ReactHTML.h2 -import react.dom.html.ReactHTML.h4 -import web.cssom.ClassName -import web.cssom.Color -import web.html.ButtonType - -import kotlinx.browser.window - -val sandboxApiUrl = "${window.location.origin}/api/sandbox" - -/** - * A view for testing config files - */ -val sandboxView: FC = FC { - useBackground(Style.SAVE_DARK) - val (debugInfo, setDebugInfo) = useState(null) - val (selectedSdk, setSelectedSdk) = useState(Sdk.Default) - val (isModalOpen, setIsModalOpen) = useState(false) - - val resultReload = useDeferredRequest { - val response = get( - "$sandboxApiUrl/get-debug-info", - Headers().withAcceptOctetStream(), - loadingHandler = ::loadingHandler, - responseHandler = ::noopResponseHandler, - ) - - if (response.ok) { - val resultDebugInfo: TestResultDebugInfo = response.decodeFromJsonString() - setDebugInfo(resultDebugInfo) - } else { - window.alert("There is no debug info yet. Try to run execution and wait until it is finished.") - } - } - - val runExecution = useDeferredRequest { - val response = post( - url = "$sandboxApiUrl/run-execution?sdk=$selectedSdk", - headers = jsonHeaders, - body = undefined, - loadingHandler = ::loadingHandler, - responseHandler = ::responseHandlerWithValidation, - ) - if (response.ok) { - window.alert("Successfully saved and started execution") - } else if (response.isConflict()) { - window.alert("There is already a running execution") - } - } - - h2 { - className = ClassName("text-center mt-3") - style = jso { color = Color("#FFFFFF") } - +"Sandbox" - } - - h4 { - className = ClassName("text-center") - +"try your SAVE configuration online" - } - debugInfo?.let { - displayModal( - isOpen = isModalOpen, - title = "Additional debug info", - classes = "modal-lg", - bodyBuilder = { displayTestResultDebugInfo(debugInfo) }, - modalStyle = largeTransparentModalStyle, - onCloseButtonPressed = { setIsModalOpen(false) }, - ) { - buttonBuilder("Ok") { setIsModalOpen(false) } - } - } - div { - className = ClassName("d-flex justify-content-center") - div { - className = ClassName(" flex-wrap col-10") - debugInfo?.let { debugInfo -> - div { - val alertStyle = when (debugInfo.testStatus) { - is Pass -> "success" - is Fail -> "danger" - is Ignored -> "secondary" - is Crash -> "danger" - else -> "info" - } - div { - className = ClassName("alert alert-$alertStyle alert-dismissible fade show") - role = "alert".unsafeCast() - div { - displayTestResultDebugInfoStatus(debugInfo) - buttonBuilder("See more details...", "link", classes = "p-0") { - setIsModalOpen(true) - } - } - button { - type = ButtonType.button - className = ClassName("align-self-center close") - asDynamic()["data-dismiss"] = "alert" - ariaLabel = "Close" - fontAwesomeIcon(icon = faTimesCircle) - onClick = { setDebugInfo(null) } - } - } - } - } - div { - className = ClassName("") - sandboxCodeEditorComponent { - editorTitle = "" - doRunExecution = runExecution - doResultReload = resultReload - } - } - div { - className = ClassName("row mt-3 mb-3") - div { - className = ClassName("col-4") - sandboxFileUploader { - getUrlForAvailableFilesFetch = { "$sandboxApiUrl/list-file" } - getUrlForFileUpload = { "$sandboxApiUrl/upload-file" } - getUrlForFileDownload = { fileInfo -> - "$sandboxApiUrl/download-file?fileName=${fileInfo.name.escapeIfNeeded()}" - } - getUrlForFileDeletion = { fileInfo -> - "$sandboxApiUrl/delete-file?fileName=${fileInfo.name.escapeIfNeeded()}" - } - } - } - div { - className = ClassName("col-8") - // ======== sdk selection ========= - sdkSelection { - title = "" - this.selectedSdk = selectedSdk - onSdkChange = { newSdk -> setSelectedSdk(newSdk) } - } - } - } - } - } -} diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/routing/BasicRouting.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/routing/BasicRouting.kt index a6b8b02447..a53d1c5369 100644 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/routing/BasicRouting.kt +++ b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/routing/BasicRouting.kt @@ -156,7 +156,6 @@ val basicRouting: FC = FC { props -> listOf( indexView.create { userInfo = props.userInfo } to "/", saveWelcomeView.create { userInfo = props.userInfo } to SAVE, - sandboxView.create() to SANDBOX, AboutUsView::class.react.create() to ABOUT_US, createOrganizationView.create() to CREATE_ORGANIZATION, registrationView.create { diff --git a/save-frontend/webpack.config.d/dev-server.js b/save-frontend/webpack.config.d/dev-server.js index 574c4ba722..79ba953645 100644 --- a/save-frontend/webpack.config.d/dev-server.js +++ b/save-frontend/webpack.config.d/dev-server.js @@ -7,17 +7,6 @@ config.devServer = Object.assign( return middlewares; }, proxy: [ - { - context: ["/api/sandbox/**"], - target: 'http://localhost:5400', - logLevel: 'debug', - onProxyReq: function (proxyReq, req, res) { - proxyReq.setHeader("X-Authorization-Id", "1"); - proxyReq.setHeader("X-Authorization-Name", "admin"); - proxyReq.setHeader("X-Authorization-Roles", "ROLE_SUPER_ADMIN"); - proxyReq.setHeader("X-Authorization-Status", "ACTIVE"); - } - }, { context: ["/api/demo/**"], target: 'http://localhost:5421', diff --git a/save-sandbox/build.gradle.kts b/save-sandbox/build.gradle.kts deleted file mode 100644 index b31de4f1a6..0000000000 --- a/save-sandbox/build.gradle.kts +++ /dev/null @@ -1,39 +0,0 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -@Suppress("DSL_SCOPE_VIOLATION", "RUN_IN_SCRIPT") // https://github.com/gradle/gradle/issues/22797 -plugins { - id("com.saveourtool.save.buildutils.kotlin-jvm-configuration") - id("com.saveourtool.save.buildutils.spring-boot-app-configuration") - id("com.saveourtool.save.buildutils.spring-data-configuration") - id("com.saveourtool.save.buildutils.save-cli-configuration") - id("com.saveourtool.save.buildutils.save-agent-configuration") - id("com.saveourtool.save.buildutils.code-quality-convention") - kotlin("plugin.allopen") - alias(libs.plugins.kotlin.plugin.jpa) -} - -kotlin { - allOpen { - annotation("javax.persistence.Entity") - } -} - -tasks.withType { - compilerOptions { - freeCompilerArgs.add("-Xcontext-receivers") - } -} - -dependencies { - implementation(projects.saveOrchestratorCommon) - implementation(libs.zip4j) - implementation(libs.spring.cloud.starter.kubernetes.client.config) - implementation(libs.hibernate.jpa21.api) - implementation(libs.save.plugins.warn.jvm) - implementation(projects.authenticationService) - implementation(libs.spring.boot.starter.security) - implementation(libs.spring.security.core) - implementation(libs.save.common.jvm) - testImplementation(projects.testUtils) - testImplementation(libs.fabric8.kubernetes.server.mock) -} diff --git a/save-sandbox/db/db.changelog-sandbox.xml b/save-sandbox/db/db.changelog-sandbox.xml deleted file mode 100644 index 7b27bed7af..0000000000 --- a/save-sandbox/db/db.changelog-sandbox.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - diff --git a/save-sandbox/db/tables/agent-status.xml b/save-sandbox/db/tables/agent-status.xml deleted file mode 100644 index b6f1b67790..0000000000 --- a/save-sandbox/db/tables/agent-status.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/save-sandbox/db/tables/agent.xml b/save-sandbox/db/tables/agent.xml deleted file mode 100644 index 78bb05256f..0000000000 --- a/save-sandbox/db/tables/agent.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/save-sandbox/db/tables/db.changelog-tables.xml b/save-sandbox/db/tables/db.changelog-tables.xml deleted file mode 100644 index 5bf99a4d66..0000000000 --- a/save-sandbox/db/tables/db.changelog-tables.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/save-sandbox/db/tables/execution.xml b/save-sandbox/db/tables/execution.xml deleted file mode 100644 index 50b231edcc..0000000000 --- a/save-sandbox/db/tables/execution.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/save-sandbox/db/tables/lnk-execution-agent.xml b/save-sandbox/db/tables/lnk-execution-agent.xml deleted file mode 100644 index 7e73c13b6e..0000000000 --- a/save-sandbox/db/tables/lnk-execution-agent.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - insert into lnk_execution_agent(execution_id, agent_id) - select execution_id, id - from agent; - - - - - - diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/SaveSandbox.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/SaveSandbox.kt deleted file mode 100644 index 023e03971b..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/SaveSandbox.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.saveourtool.save.sandbox - -import com.saveourtool.save.s3.DefaultS3Configuration -import com.saveourtool.save.sandbox.config.ConfigProperties -import org.springframework.boot.SpringApplication -import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.boot.autoconfigure.domain.EntityScan -import org.springframework.boot.context.properties.EnableConfigurationProperties -import org.springframework.context.annotation.Import - -/** - * An entrypoint for spring boot for save-sandbox - */ -@SpringBootApplication -@EnableConfigurationProperties(ConfigProperties::class) -@Import(DefaultS3Configuration::class) -@EntityScan( - "com.saveourtool.save.entities", - "com.saveourtool.save.sandbox.entity", -) -open class SaveSandbox - -fun main(args: Array) { - SpringApplication.run(SaveSandbox::class.java, *args) -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/ConfigProperties.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/ConfigProperties.kt deleted file mode 100644 index 4a7d3b8205..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/ConfigProperties.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.saveourtool.save.sandbox.config - -import com.saveourtool.save.s3.S3OperationsProperties -import com.saveourtool.save.service.LokiConfig -import org.springframework.boot.context.properties.ConfigurationProperties -import org.springframework.boot.context.properties.ConstructorBinding - -/** - * @property s3Storage configuration of S3 storage - * @property agentSettings properties for save-agents - * @property lokiConfig config of loki service for logging - */ -@ConstructorBinding -@ConfigurationProperties(prefix = "sandbox") -data class ConfigProperties( - override val s3Storage: S3OperationsProperties, - val agentSettings: AgentSettings, - val lokiConfig: LokiConfig? = null, -) : S3OperationsProperties.Provider { - /** - * @property sandboxUrl the URL of save-sandbox that will be reported to save-agents. - */ - data class AgentSettings( - val sandboxUrl: String, - ) -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/LogServiceConfig.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/LogServiceConfig.kt deleted file mode 100644 index 3c60ca31ea..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/LogServiceConfig.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.saveourtool.save.sandbox.config - -import com.saveourtool.save.service.LogService -import com.saveourtool.save.service.LokiLogService -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration - -/** - * Spring's configuration to configure [LogService] - */ -@Configuration -class LogServiceConfig { - /** - * @param configProperties - * @return [LokiLogService] when properties *sandbox.loki.** are set - */ - @Bean - fun logService( - configProperties: ConfigProperties, - ): LogService = LokiLogService.createOrStub(configProperties.lokiConfig) -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/WebSecurityConfig.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/WebSecurityConfig.kt deleted file mode 100644 index 843e20c46d..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/config/WebSecurityConfig.kt +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Configuration beans for security in different profiles - */ - -package com.saveourtool.save.sandbox.config - -import com.saveourtool.save.authservice.config.NoopWebSecurityConfig -import com.saveourtool.save.authservice.config.WebSecurityConfig -import org.springframework.context.annotation.Import -import org.springframework.context.annotation.Profile -import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity - -@EnableWebFluxSecurity -@EnableReactiveMethodSecurity -@Profile("secure") -@Import( - WebSecurityConfig::class, -) -@Suppress("MISSING_KDOC_TOP_LEVEL", "MISSING_KDOC_CLASS_ELEMENTS", "MISSING_KDOC_ON_FUNCTION") -class SandboxWebSecurityConfig - -@EnableWebFluxSecurity -@Profile("!secure") -@Import(NoopWebSecurityConfig::class) -@Suppress("MISSING_KDOC_TOP_LEVEL", "MISSING_KDOC_CLASS_ELEMENTS", "MISSING_KDOC_ON_FUNCTION") -class SandboxNoopWebSecurityConfig diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/controller/SandboxController.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/controller/SandboxController.kt deleted file mode 100644 index 84c3840488..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/controller/SandboxController.kt +++ /dev/null @@ -1,466 +0,0 @@ -package com.saveourtool.save.sandbox.controller - -import com.saveourtool.save.authservice.utils.userId -import com.saveourtool.save.authservice.utils.username -import com.saveourtool.save.configs.ApiSwaggerSupport -import com.saveourtool.save.domain.SandboxFileInfo -import com.saveourtool.save.execution.ExecutionStatus -import com.saveourtool.save.orchestrator.config.ConfigProperties -import com.saveourtool.save.orchestrator.controller.AgentsController -import com.saveourtool.save.sandbox.entity.SandboxExecution -import com.saveourtool.save.sandbox.repository.SandboxAgentRepository -import com.saveourtool.save.sandbox.repository.SandboxAgentStatusRepository -import com.saveourtool.save.sandbox.repository.SandboxExecutionRepository -import com.saveourtool.save.sandbox.repository.SandboxLnkExecutionAgentRepository -import com.saveourtool.save.sandbox.service.SandboxOrchestratorAgentService -import com.saveourtool.save.sandbox.storage.SandboxStorage -import com.saveourtool.save.sandbox.storage.SandboxStorageKey -import com.saveourtool.save.sandbox.storage.SandboxStorageKeyType -import com.saveourtool.save.service.LogService -import com.saveourtool.save.utils.* -import generated.SAVE_CLI_VERSION - -import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.Parameters -import io.swagger.v3.oas.annotations.enums.ParameterIn -import io.swagger.v3.oas.annotations.responses.ApiResponse -import io.swagger.v3.oas.annotations.tags.Tag -import io.swagger.v3.oas.annotations.tags.Tags -import org.intellij.lang.annotations.Language -import org.springframework.http.HttpStatus -import org.springframework.http.MediaType -import org.springframework.http.codec.multipart.FilePart -import org.springframework.security.core.Authentication -import org.springframework.web.bind.annotation.* -import reactor.core.publisher.Flux -import reactor.core.publisher.Mono -import reactor.kotlin.core.publisher.toMono -import reactor.kotlin.core.util.function.component1 -import reactor.kotlin.core.util.function.component2 - -import java.nio.ByteBuffer -import java.time.LocalDateTime -import javax.transaction.Transactional - -/** - * @property configProperties - * @property storage - * @property sandboxExecutionRepository - * @property sandboxAgentRepository - * @property sandboxAgentStatusRepository - * @property sandboxLnkExecutionAgentRepository - * @property agentsController - * @property orchestratorAgentService - * @property logService - */ -@ApiSwaggerSupport -@Tags( - Tag(name = "sandbox"), -) -@RestController -@RequestMapping("/api/sandbox") -@SuppressWarnings("LongParameterList") -class SandboxController( - val configProperties: ConfigProperties, - val storage: SandboxStorage, - val sandboxExecutionRepository: SandboxExecutionRepository, - val sandboxAgentRepository: SandboxAgentRepository, - val sandboxAgentStatusRepository: SandboxAgentStatusRepository, - val sandboxLnkExecutionAgentRepository: SandboxLnkExecutionAgentRepository, - val agentsController: AgentsController, - val orchestratorAgentService: SandboxOrchestratorAgentService, - val logService: LogService, -) { - @Operation( - method = "GET", - summary = "Get a list of files for provided user", - description = "Get a list of files for provided user", - ) - @ApiResponse(responseCode = "200", description = "A list of files") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @GetMapping("/list-file") - fun listFiles( - authentication: Authentication, - ): Flux = Mono.just(authentication.userId()) - .flatMapMany { userId -> - storage.list(userId, SandboxStorageKeyType.FILE) - } - .flatMap { - Mono.zip( - it.toMono(), - storage.contentLength(it), - ) - } - .map { (storageKey, size) -> - SandboxFileInfo(storageKey.fileName, size) - } - - @Operation( - method = "POST", - summary = "Upload a file for provided user", - description = "Upload a file for provided user", - ) - @Parameters( - Parameter(name = FILE_PART_NAME, `in` = ParameterIn.DEFAULT, description = "a file which needs to be uploaded", required = true), - Parameter(name = CONTENT_LENGTH_CUSTOM, `in` = ParameterIn.HEADER, description = "size in bytes of a file", required = true), - ) - @ApiResponse(responseCode = "200", description = "Uploaded bytes") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @PostMapping("/upload-file", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) - fun uploadFile( - @RequestPart file: Mono, - @RequestHeader(CONTENT_LENGTH_CUSTOM) contentLength: Long, - authentication: Authentication, - ): Mono = file.flatMap { filePart -> - getAsMonoStorageKey(authentication.userId(), SandboxStorageKeyType.FILE, filePart.filename()) - .flatMap { key -> - storage.overwrite( - key = key, - content = filePart, - contentLength = contentLength, - ) - } - .map { - SandboxFileInfo(filePart.filename(), contentLength) - } - } - - @Operation( - method = "POST", - summary = "Upload a file as text for provided user with provide file name", - description = "Upload a file as text for provided user with provide file name", - ) - @Parameters( - Parameter(name = "fileName", `in` = ParameterIn.QUERY, description = "file name", required = true), - Parameter(name = "content", `in` = ParameterIn.DEFAULT, description = "a content of an uploading file", required = true), - ) - @ApiResponse(responseCode = "200", description = "Uploaded bytes") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @PostMapping("/upload-file-as-text") - fun uploadFileAsText( - @RequestParam fileName: String, - @RequestBody content: String, - authentication: Authentication, - ): Mono = doUploadAsText(authentication.userId(), SandboxStorageKeyType.FILE, fileName, content) - - @Operation( - method = "GET", - summary = "Get a file for provided user with requested file name", - description = "Get a file for provided user with requested file name", - ) - @Parameters( - Parameter(name = "fileName", `in` = ParameterIn.QUERY, description = "file name", required = true), - ) - @ApiResponse(responseCode = "200", description = "Contest of a requested file") - @ApiResponse(responseCode = "404", description = "User with such name or file with such file name and user was not found") - @GetMapping("/download-file", produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE]) - fun downloadFile( - @RequestParam fileName: String, - authentication: Authentication, - ): Flux = getAsMonoStorageKey(authentication.userId(), SandboxStorageKeyType.FILE, fileName) - .flatMapMany { - storage.download(it) - } - .switchIfEmptyToNotFound { - "There is no file $fileName for user ${authentication.username()}" - } - - @Operation( - method = "GET", - summary = "Download a file as text for provided user and requested file name", - description = "Download a file as text for provided user and requested file name", - ) - @Parameters( - Parameter(name = "fileName", `in` = ParameterIn.QUERY, description = "file name", required = true), - ) - @ApiResponse(responseCode = "200", description = "Content of the file as text") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @GetMapping("/download-file-as-text") - fun downloadFileAsText( - @RequestParam fileName: String, - authentication: Authentication, - ): Mono = doDownloadAsText(authentication.userId(), SandboxStorageKeyType.FILE, fileName) - - @Operation( - method = "DELETE", - summary = "Delete a file for provided user with requested file name", - description = "Delete a file for provided user with requested file name", - ) - @Parameters( - Parameter(name = "fileName", `in` = ParameterIn.QUERY, description = "file name", required = true), - ) - @ApiResponse(responseCode = "200", description = "Result of delete operation of a requested file") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @DeleteMapping("/delete-file") - fun deleteFile( - @RequestParam fileName: String, - authentication: Authentication, - ): Mono = getAsMonoStorageKey(authentication.userId(), SandboxStorageKeyType.FILE, fileName) - .flatMap { - storage.delete(it) - } - - @Operation( - method = "POST", - summary = "Upload a test file as text for provided user with provide file name", - description = "Upload a test file as text for provided user with provide file name", - ) - @Parameters( - Parameter(name = "fileName", `in` = ParameterIn.QUERY, description = "file name", required = true), - Parameter(name = "content", `in` = ParameterIn.DEFAULT, description = "a content of an uploading file", required = true), - ) - @ApiResponse(responseCode = "200", description = "Uploaded bytes") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @PostMapping("/upload-test-as-text") - fun uploadTestAsText( - @RequestParam fileName: String, - @RequestBody content: String, - authentication: Authentication, - ): Mono = doUploadAsText(authentication.userId(), SandboxStorageKeyType.TEST, fileName, content) - - private fun doUploadAsText( - userId: Long, - type: SandboxStorageKeyType, - fileName: String, - content: String, - ): Mono = getAsMonoStorageKey(userId, type, fileName) - .flatMap { key -> - storage.overwrite( - key = key, - contentBytes = content.replace("\r\n?".toRegex(), "\n").toByteArray(), - ) - } - .map { - SandboxFileInfo(fileName, it) - } - - @Operation( - method = "GET", - summary = "Download a test file as text for provided user and requested file name", - description = "Download a test file as text for provided user and requested file name", - ) - @Parameters( - Parameter(name = "fileName", `in` = ParameterIn.QUERY, description = "file name", required = true), - ) - @ApiResponse(responseCode = "200", description = "Content of the test file as text") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @GetMapping("/download-test-as-text") - fun downloadTestAsText( - @RequestParam fileName: String, - authentication: Authentication, - ): Mono = doDownloadAsText(authentication.userId(), SandboxStorageKeyType.TEST, fileName) - - private fun doDownloadAsText( - userId: Long, - type: SandboxStorageKeyType, - fileName: String, - ): Mono = getAsMonoStorageKey(userId, type, fileName) - .flatMap { key -> - storage.download(key) - .collectToInputStream() - .map { it.bufferedReader().readText() } - } - .switchIfEmpty( - examples[fileName].toMono() - .flatMap { example -> - doUploadAsText(userId, type, fileName, example) - .thenReturn(example) - } - .switchIfEmptyToNotFound { - "There is no test file $fileName for user id $userId" - } - ) - - private fun getAsMonoStorageKey( - userId: Long, - type: SandboxStorageKeyType, - fileName: String, - ): Mono = Mono.just(userId) - .map { uid -> - SandboxStorageKey( - uid, - type, - fileName, - ) - } - - @Operation( - method = "GET", - summary = "Download a debug info for provided user", - description = "Download a debug info for provided user", - ) - @ApiResponse(responseCode = "200", description = "Content of the debug info") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @GetMapping(path = ["/get-debug-info"], produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE]) - fun getDebugInfo( - authentication: Authentication, - ): Flux = Mono.just(authentication.userId()) - .flatMapMany { userId -> - storage.download(SandboxStorageKey.debugInfoKey(userId)) - } - .switchIfEmptyToNotFound { - "There is no DebugInfo for ${authentication.username()}" - } - - @Operation( - method = "POST", - summary = "Run a new execution for provided user", - description = "Run a new execution for provided user", - ) - @Parameters( - Parameter(name = "sdk", `in` = ParameterIn.QUERY, description = "SDK", required = true), - ) - @ApiResponse(responseCode = "200", description = "empty response for execution run") - @ApiResponse(responseCode = "404", description = "User with such name was not found") - @ApiResponse(responseCode = "409", description = "There is a running execution") - @PostMapping("/run-execution") - @Transactional - fun runExecution( - @RequestParam sdk: String, - authentication: Authentication, - ): Mono { - val userId = authentication.userId() - return validateNoRunningExecution(userId) - .flatMap { - storage.delete(SandboxStorageKey.debugInfoKey(userId)) - } - .flatMap { - blockingToMono { - val execution = SandboxExecution( - startTime = LocalDateTime.now(), - endTime = null, - status = ExecutionStatus.PENDING, - sdk = sdk, - saveCliVersion = SAVE_CLI_VERSION, - userId = userId, - initialized = false, - failReason = null, - ) - sandboxExecutionRepository.save(execution) - } - } - .map { orchestratorAgentService.getRunRequest(it) } - .flatMap { request -> - agentsController.initialize(request) - } - } - - /** - * @param limit - * @param authentication - * @return logs from agent sandbox - */ - @GetMapping("/logs-from-agent") - fun getAgentLogs( - @RequestParam(required = false, defaultValue = "1000") limit: Int, - authentication: Authentication, - ): Mono = blockingToMono { - sandboxExecutionRepository.findTopByUserIdOrderByStartTimeDesc(authentication.userId()) - } - .switchIfEmptyToNotFound { - "There is no run for ${authentication.username()} yet" - } - .flatMap { execution -> - val agent = sandboxLnkExecutionAgentRepository.findByExecutionId(execution.requiredId()) - .singleOrNull() - .orConflict { "Only a single agent expected for execution ${execution.requiredId()}" } - .agent - val startTime = sandboxAgentStatusRepository.findTopByAgentOrderByStartTimeAsc(agent) - ?.startTime - .orNotFound { "Not found first agent status for execution ${execution.requiredId()}" } - val endTime = sandboxAgentStatusRepository.findTopByAgentOrderByEndTimeDesc(agent) - ?.endTime - .orNotFound { "Not found latest agent status for execution ${execution.requiredId()}" } - logService.getByContainerName(agent.containerName, - startTime.toInstantAtDefaultZone(), - endTime.toInstantAtDefaultZone(), - limit, - ) - } - - private fun validateNoRunningExecution( - userId: Long, - ): Mono = blockingToMono { - sandboxExecutionRepository.findByUserId(userId) - .filter { it.status in setOf(ExecutionStatus.RUNNING, ExecutionStatus.PENDING) } - } - .requireOrSwitchToResponseException({ isEmpty() }, HttpStatus.CONFLICT) { - "There is already a running execution" - } - .thenReturn(Unit) - - companion object { - @Language("toml") - private val saveTomlExample = """ - |# special configuration file to use save test framework: https://github.com/saveourtool/save-cli - |[general] - |execCmd = "python -m pylint" - |# === example of expected tests CHECK-MESSAGES: :[[@LINE-1]]:12: warning: test [warning-name] === - |expectedWarningsPattern = "# CHECK-MESSAGES:?\\[\\[(.+)\\]\\]: (.*)" - | - |tags = ["check_only", "clang_tidy", "huawei_specific"] - |description = "Demo suite of Huawei specific tests for Clang tidy" - |suiteName = "Fixbot codecheck-python tests" - | - | - |[warn] - |actualWarningsPattern=".*[\\\\\\/](.*):(\\d+): (.*)" - | - |execFlags = "--msg-template=\"{path}:{line}: {msg_id}: {msg} ({symbol})\"" - |linePlaceholder = "@LINE" - | - |exactWarningsMatch = false - |partialWarnTextMatch = true - |testNameRegex = ".*test.*" - |#testNameRegex = ".*.py" - |warningTextHasColumn = false - |warningTextHasLine = true - | - |lineCaptureGroup = 1 - |#columnCaptureGroup = null - |messageCaptureGroup = 2 - | - | - |fileNameCaptureGroupOut = 1 - |lineCaptureGroupOut = 2 - |#columnCaptureGroupOut = null - |messageCaptureGroupOut = 3 - """.trimMargin() - - @Language("python") - private val testExample = """ - |# CHECK-MESSAGES:[[1]]: C0114: Missing module docstring (missing-module-docstring) - |import tkinter as tk - | - |root=tk.Tk() - | - |canvas1 = tk.Canvas(root, width = 300, height = 300) - |canvas1.pack() - | - |# CHECK-MESSAGES:[[10]]: C0116: Missing function or method docstring (missing-function-docstring) - |def hello (): - | label1 = tk.Label(root, text= 'Hello World!', fg='blue', font=('helvetica', 12, 'bold')) - | canvas1.create_window(150, 200, window=label1) - | - |button1 = tk.Button(text='Click Me', command=hello, bg='brown',fg='white') - |canvas1.create_window(150, 150, window=button1) - | - |root.mainloop() - """.trimMargin() - - @Language("bash") - private val setupShExample = """ - |#!/usr/bin/env bash - | - |# Here you can add some additional commands required to run your tool e.g. - |# setup pylint, it setups all required dependencies - |pip install pylint --no-input --disable-pip-version-check --no-warn-script-location - """.trimMargin() - private val examples = mapOf( - "test" to testExample, - "save.toml" to saveTomlExample, - "setup.sh" to setupShExample, - ) - } -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/controller/SandboxInternalController.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/controller/SandboxInternalController.kt deleted file mode 100644 index b595fc027f..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/controller/SandboxInternalController.kt +++ /dev/null @@ -1,129 +0,0 @@ -package com.saveourtool.save.sandbox.controller - -import com.saveourtool.save.agent.TestExecutionResult -import com.saveourtool.save.domain.TestResultDebugInfo -import com.saveourtool.save.sandbox.storage.SandboxStorage -import com.saveourtool.save.sandbox.storage.SandboxStorageKey -import com.saveourtool.save.sandbox.storage.SandboxStorageKeyType -import com.saveourtool.save.utils.* - -import com.fasterxml.jackson.databind.ObjectMapper -import org.apache.commons.io.FileUtils -import org.apache.commons.io.IOUtils -import org.springframework.http.MediaType -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.* -import reactor.core.publisher.Flux -import reactor.core.publisher.Mono -import reactor.kotlin.core.publisher.toMono - -import java.nio.ByteBuffer - -import kotlin.io.path.createTempDirectory -import kotlin.io.path.createTempFile -import kotlin.io.path.deleteExisting -import kotlin.io.path.outputStream - -typealias ByteBufferFluxResponse = ResponseEntity> - -/** - * Sandbox implementation of endpoints which are required for save-agent - */ -@RestController -@RequestMapping("/internal/sandbox") -class SandboxInternalController( - private val storage: SandboxStorage, - private val objectMapper: ObjectMapper, -) { - /** - * @param userId ID of User - * @return content of requested snapshot - */ - @PostMapping( - "/download-test-files", - produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE] - ) - fun downloadTestFiles( - @RequestParam userId: Long, - ): Mono { - val archiveFile = createTempFile( - prefix = "tests-", - suffix = ZIP_ARCHIVE_EXTENSION - ) - return { createTempDirectory(prefix = "tests-directory-") } - .toMono() - .flatMap { directory -> - storage.list(userId, SandboxStorageKeyType.TEST) - .flatMap { key -> - storage.download(key) - .collectToInputStream() - .map { inputStream -> - directory.resolve(key.fileName) - .outputStream() - .use { - IOUtils.copy(inputStream, it) - } - } - } - .collectList() - .map { - directory.compressAsZipTo(archiveFile) - FileUtils.deleteDirectory(directory.toFile()) - } - } - .map { - archiveFile.toByteBufferFlux() - } - .map { - ResponseEntity.ok(it) - } - .doFinally { - archiveFile.deleteExisting() - } - } - - /** - * @param userId ID of User - * @param fileName - * @return content of requested file - */ - @PostMapping("/download-file", produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE]) - fun downloadFile( - @RequestParam userId: Long, - @RequestParam fileName: String, - ): Mono = blockingToMono { - ResponseEntity.ok( - storage.download( - SandboxStorageKey( - userId = userId, - type = SandboxStorageKeyType.FILE, - fileName = fileName, - ) - ) - ) - } - - /** - * @param testExecutionResults - * @return response with text value - */ - @PostMapping("/upload-execution-data") - fun saveExecutionData( - @Suppress("UnusedParameter") @RequestBody testExecutionResults: List - ): Mono = ResponseEntity.ok("Do nothing for now") - .toMono() - - /** - * @param userId - * @param testResultDebugInfo - * @return [Mono] with count of uploaded bytes - */ - @PostMapping("/upload-debug-info") - fun uploadDebugInfo( - @RequestParam userId: Long, - @RequestBody testResultDebugInfo: TestResultDebugInfo, - ): Mono = storage.overwrite( - key = SandboxStorageKey.debugInfoKey(userId), - contentBytes = objectMapper.writeValueAsBytes(testResultDebugInfo) - ) -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/entity/SandboxExecution.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/entity/SandboxExecution.kt deleted file mode 100644 index 6dc6e77a7b..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/entity/SandboxExecution.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.saveourtool.save.sandbox.entity - -import com.saveourtool.save.domain.toSdk -import com.saveourtool.save.entities.Execution -import com.saveourtool.save.execution.ExecutionStatus -import com.saveourtool.save.request.RunExecutionRequest -import com.saveourtool.save.spring.entity.BaseEntity -import java.net.URL - -import java.time.LocalDateTime -import javax.persistence.* - -/** - * @property startTime - * @property endTime - * @property status - * @property sdk - * @property saveCliVersion - * @property userId - * @property initialized - * @property failReason - */ -@Entity -@Table(name = "execution") -@Suppress("LongParameterList") -class SandboxExecution( - var startTime: LocalDateTime, - var endTime: LocalDateTime?, - @Enumerated(EnumType.STRING) - var status: ExecutionStatus, - var sdk: String, - var saveCliVersion: String, - @Column(name = "user_id") - var userId: Long, - var initialized: Boolean, - var failReason: String?, -) : BaseEntity() { - /** - * @param saveAgentUrl an url to download save-agent - * @return [RunExecutionRequest] created from current entity - */ - fun toRunRequest( - saveAgentUrl: URL, - ): RunExecutionRequest { - require(status == ExecutionStatus.PENDING) { - "${RunExecutionRequest::class.simpleName} can be created only for ${Execution::class.simpleName} with status = ${ExecutionStatus.PENDING}" - } - return RunExecutionRequest( - executionId = requiredId(), - sdk = sdk.toSdk(), - saveAgentUrl = saveAgentUrl.toString(), - ) - } -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/entity/SandboxLnkExecutionAgent.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/entity/SandboxLnkExecutionAgent.kt deleted file mode 100644 index 9629fc062b..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/entity/SandboxLnkExecutionAgent.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.saveourtool.save.sandbox.entity - -import com.saveourtool.save.entities.Agent -import com.saveourtool.save.spring.entity.BaseEntity -import javax.persistence.Entity -import javax.persistence.JoinColumn -import javax.persistence.ManyToOne -import javax.persistence.Table - -/** - * @property execution execution that is connected to [agent] - * @property agent agent assigned to [execution] - */ -@Entity -@Table(name = "lnk_execution_agent") -class SandboxLnkExecutionAgent( - @ManyToOne - @JoinColumn(name = "execution_id") - var execution: SandboxExecution, - - @ManyToOne - @JoinColumn(name = "agent_id") - var agent: Agent, -) : BaseEntity() diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxAgentRepository.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxAgentRepository.kt deleted file mode 100644 index 62f173114d..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxAgentRepository.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.saveourtool.save.sandbox.repository - -import com.saveourtool.save.entities.Agent -import com.saveourtool.save.spring.repository.BaseEntityRepository -import org.springframework.stereotype.Repository - -/** - * Repository for [Agent] - */ -@Repository -interface SandboxAgentRepository : BaseEntityRepository { - /** - * Find agent by its container id - * - * @param containerId - * @return [Agent] - */ - fun findByContainerId(containerId: String): Agent? -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxAgentStatusRepository.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxAgentStatusRepository.kt deleted file mode 100644 index 5abeb9e2d5..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxAgentStatusRepository.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.saveourtool.save.sandbox.repository - -import com.saveourtool.save.entities.Agent -import com.saveourtool.save.entities.AgentStatus -import com.saveourtool.save.spring.repository.BaseEntityRepository -import org.springframework.stereotype.Repository - -/** - * Repository for [AgentStatus] in sandbox - */ -@Repository -interface SandboxAgentStatusRepository : BaseEntityRepository { - /** - * Find latest [AgentStatus] for agent with provided [containerId] - * - * @param containerId id of an agent - * @return [AgentStatus] of an agent - */ - fun findTopByAgentContainerIdOrderByEndTimeDescIdDesc(containerId: String): AgentStatus? - - /** - * Find [AgentStatus] by [Agent] which is first by [AgentStatus.startTime] - * - * @param agent - * @return [AgentStatus] which fits to query - */ - fun findTopByAgentOrderByStartTimeAsc(agent: Agent): AgentStatus? - - /** - * Find [AgentStatus] by [Agent] which is last by [AgentStatus.endTime] - * - * @param agent - * @return [AgentStatus] which fits to query - */ - fun findTopByAgentOrderByEndTimeDesc(agent: Agent): AgentStatus? -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxExecutionRepository.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxExecutionRepository.kt deleted file mode 100644 index e0a1090e08..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxExecutionRepository.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.saveourtool.save.sandbox.repository - -import com.saveourtool.save.sandbox.entity.SandboxExecution -import com.saveourtool.save.spring.repository.BaseEntityRepository -import org.springframework.stereotype.Repository - -/** - * Repository for [SandboxExecution] - */ -@Repository -interface SandboxExecutionRepository : BaseEntityRepository { - /** - * @param userId - * @return list of [SandboxExecution] for requested [userId] - */ - fun findByUserId(userId: Long): List - - /** - * @param userId - * @return latest [SandboxExecution] for requested [userId] - */ - fun findTopByUserIdOrderByStartTimeDesc(userId: Long): SandboxExecution? -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxLnkExecutionAgentRepository.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxLnkExecutionAgentRepository.kt deleted file mode 100644 index d1bc2831c6..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/repository/SandboxLnkExecutionAgentRepository.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.saveourtool.save.sandbox.repository - -import com.saveourtool.save.sandbox.entity.SandboxLnkExecutionAgent -import com.saveourtool.save.spring.repository.BaseEntityRepository - -/** - * Repository of [SandboxLnkExecutionAgent] - */ -interface SandboxLnkExecutionAgentRepository : BaseEntityRepository { - /** - * @param agentId ID of [com.saveourtool.save.entities.Agent] - * @return [SandboxLnkExecutionAgent] or null - */ - fun findByAgentId(agentId: Long): SandboxLnkExecutionAgent? - - /** - * @param executionId ID of [com.saveourtool.save.sandbox.entity.SandboxExecution] - * @return list of [SandboxLnkExecutionAgent] - */ - fun findByExecutionId(executionId: Long): List -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/service/SandboxOrchestratorAgentService.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/service/SandboxOrchestratorAgentService.kt deleted file mode 100644 index 4b4ef25726..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/service/SandboxOrchestratorAgentService.kt +++ /dev/null @@ -1,183 +0,0 @@ -package com.saveourtool.save.sandbox.service - -import com.saveourtool.save.agent.AgentInitConfig -import com.saveourtool.save.agent.AgentRunConfig -import com.saveourtool.save.agent.SaveCliOverrides -import com.saveourtool.save.entities.* -import com.saveourtool.save.execution.ExecutionStatus -import com.saveourtool.save.orchestrator.service.OrchestratorAgentService -import com.saveourtool.save.orchestrator.service.TestExecutionList -import com.saveourtool.save.request.RunExecutionRequest -import com.saveourtool.save.sandbox.config.ConfigProperties -import com.saveourtool.save.sandbox.entity.SandboxExecution -import com.saveourtool.save.sandbox.entity.SandboxLnkExecutionAgent -import com.saveourtool.save.sandbox.repository.SandboxAgentRepository -import com.saveourtool.save.sandbox.repository.SandboxAgentStatusRepository -import com.saveourtool.save.sandbox.repository.SandboxExecutionRepository -import com.saveourtool.save.sandbox.repository.SandboxLnkExecutionAgentRepository -import com.saveourtool.save.sandbox.storage.SandboxInternalFileStorage -import com.saveourtool.save.sandbox.storage.SandboxStorage -import com.saveourtool.save.sandbox.storage.SandboxStorageKeyType -import com.saveourtool.save.storage.impl.InternalFileKey -import com.saveourtool.save.utils.* - -import org.springframework.data.repository.findByIdOrNull -import org.springframework.http.ResponseEntity -import org.springframework.stereotype.Component -import reactor.core.publisher.Mono -import reactor.kotlin.core.publisher.toMono -import reactor.kotlin.core.util.function.component1 -import reactor.kotlin.core.util.function.component2 -import java.util.stream.Collectors - -/** - * Sandbox implementation for agent service - */ -@Component("SandboxAgentRepositoryForOrchestrator") -@Suppress("LongParameterList") -class SandboxOrchestratorAgentService( - private val sandboxAgentRepository: SandboxAgentRepository, - private val sandboxAgentStatusRepository: SandboxAgentStatusRepository, - private val sandboxLnkExecutionAgentRepository: SandboxLnkExecutionAgentRepository, - private val sandboxExecutionRepository: SandboxExecutionRepository, - private val sandboxStorage: SandboxStorage, - private val internalFileStorage: SandboxInternalFileStorage, - configProperties: ConfigProperties, -) : OrchestratorAgentService { - private val sandboxUrlForAgent = "${configProperties.agentSettings.sandboxUrl}/internal/sandbox" - - override fun getInitConfig(containerId: String): Mono = getExecutionAsMonoByContainerId(containerId) - .zipWhen { execution -> - sandboxStorage.list(execution.userId, SandboxStorageKeyType.FILE) - .map { storageKey -> - storageKey.fileName to "$sandboxUrlForAgent/download-file?userId=${storageKey.userId}&fileName=${storageKey.fileName}" - } - .collectList() - .map { - it.toMap() - } - } - .map { (execution, fileToUrls) -> - AgentInitConfig( - saveCliUrl = internalFileStorage.generateRequiredUrlToDownloadFromContainer(InternalFileKey.saveCliKey(execution.saveCliVersion)) - .toString(), - testSuitesSourceSnapshotUrl = "$sandboxUrlForAgent/download-test-files?userId=${execution.userId}", - additionalFileNameToUrl = fileToUrls, - // sandbox doesn't support save-cli overrides for now - saveCliOverrides = SaveCliOverrides(), - ) - } - - override fun getNextRunConfig(containerId: String): Mono = getExecutionAsMonoByContainerId(containerId) - .filter { !it.initialized } - .map { execution -> sandboxExecutionRepository.save(execution.apply { initialized = true }) } - .flatMap { execution -> - sandboxStorage.list(execution.userId, SandboxStorageKeyType.TEST) - .map { it.fileName } - .filter { it.endsWith("save.toml") } - .collect(Collectors.joining(" ")) - .zipWith(execution.userId.toMono()) - } - .map { (cliArgs, userId) -> - AgentRunConfig( - cliArgs = cliArgs, - executionDataUploadUrl = "$sandboxUrlForAgent/upload-execution-data", - debugInfoUploadUrl = "$sandboxUrlForAgent/upload-debug-info?userId=$userId", - ) - } - - override fun addAgent(executionId: Long, agent: AgentDto): Mono = getExecutionAsMono(executionId) - .map { execution -> - val savedAgent = sandboxAgentRepository.save(agent.toEntity()) - sandboxLnkExecutionAgentRepository.save(SandboxLnkExecutionAgent( - execution = execution, - agent = savedAgent - )) - ResponseEntity.ok().build() - } - - override fun updateAgentStatus(agentStatus: AgentStatusDto): Mono = blockingToMono { - sandboxAgentStatusRepository.save(agentStatus.toEntity(this::getAgent)) - .let { - ResponseEntity.ok().build() - } - } - - override fun getReadyForTestingTestExecutions(containerId: String): Mono = Mono.fromCallable { - // sandbox doesn't have TestExecution at all - emptyList() - } - - override fun getExecutionStatus(executionId: Long): Mono = getExecutionAsMono(executionId) - .map { it.status } - - override fun updateExecutionStatus( - executionId: Long, - executionStatus: ExecutionStatus, - failReason: String? - ): Mono = getExecutionAsMono(executionId) - .map { execution -> - sandboxExecutionRepository.save( - execution.apply { - this.status = executionStatus - this.failReason = failReason - } - ) - } - .thenReturn(ResponseEntity.ok().build()) - - override fun getAgentStatusesByExecutionId(executionId: Long): Mono = getExecutionAsMono(executionId) - .map { execution -> - sandboxLnkExecutionAgentRepository.findByExecutionId(execution.requiredId()) - .map { it.agent } - .map { agent -> - sandboxAgentStatusRepository.findTopByAgentContainerIdOrderByEndTimeDescIdDesc(agent.containerId) - .orNotFound { - "AgentStatus not found for agent id=${agent.containerId}" - } - } - .map { - it.toDto() - } - } - - override fun markReadyForTestingTestExecutionsOfAgentAsFailed(containerId: String): Mono = Mono.fromCallable { - // sandbox doesn't have TestExecution - ResponseEntity.ok().build() - } - - override fun markAllTestExecutionsOfExecutionAsFailed(executionId: Long): Mono = Mono.fromCallable { - // sandbox doesn't have TestExecution - ResponseEntity.ok().build() - } - - /** - * @param execution - * @return a request to run execution - */ - fun getRunRequest(execution: SandboxExecution): RunExecutionRequest = execution.toRunRequest( - saveAgentUrl = internalFileStorage.generateRequiredUrlToDownloadFromContainer(InternalFileKey.saveAgentKey), - ) - - private fun getExecution(executionId: Long): SandboxExecution = sandboxExecutionRepository - .findByIdOrNull(executionId) - .orNotFound { "No execution with id $executionId" } - - private fun getExecutionAsMono(executionId: Long): Mono = blockingToMono { - getExecution(executionId) - } - - private fun getAgent(containerId: String): Agent = sandboxAgentRepository - .findByContainerId(containerId) - .orNotFound { - "No agent with containerId $containerId" - } - - private fun getExecutionAsMonoByContainerId(containerId: String): Mono = blockingToMono { - sandboxLnkExecutionAgentRepository.findByAgentId(getAgent(containerId).requiredId()) - .orNotFound { - "No linked execution to agent with containerId $containerId" - } - .execution - } -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxInternalFileStorage.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxInternalFileStorage.kt deleted file mode 100644 index 60496fbd5f..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxInternalFileStorage.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.saveourtool.save.sandbox.storage - -import com.saveourtool.save.s3.S3Operations -import com.saveourtool.save.sandbox.config.ConfigProperties -import com.saveourtool.save.storage.DefaultStorageCoroutines -import com.saveourtool.save.storage.impl.AbstractInternalFileStorage -import com.saveourtool.save.storage.impl.InternalFileKey -import generated.SAVE_CLI_VERSION -import org.springframework.stereotype.Component - -/** - * Storage for internal files used by sandbox: save-cli and save-agent - */ -@Component -class SandboxInternalFileStorage( - configProperties: ConfigProperties, - s3Operations: S3Operations, -) : AbstractInternalFileStorage( - listOf(InternalFileKey.saveAgentKey, InternalFileKey.saveCliKey(SAVE_CLI_VERSION)), - configProperties.s3Storage.prefix, - s3Operations, -) { - override suspend fun doInitAdditionally(underlying: DefaultStorageCoroutines) { - underlying.downloadSaveCliFromGithub() - } -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorage.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorage.kt deleted file mode 100644 index 031c0ce1e0..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorage.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.saveourtool.save.sandbox.storage - -import com.saveourtool.save.s3.S3Operations -import com.saveourtool.save.sandbox.config.ConfigProperties -import com.saveourtool.save.storage.AbstractSimpleReactiveStorage -import com.saveourtool.save.storage.PATH_DELIMITER -import com.saveourtool.save.storage.concatS3Key -import org.springframework.stereotype.Component -import reactor.core.publisher.Flux - -/** - * Storage implementation for sandbox - */ -@Component -class SandboxStorage( - configProperties: ConfigProperties, - s3Operations: S3Operations, -) : AbstractSimpleReactiveStorage( - s3Operations, - concatS3Key(configProperties.s3Storage.prefix, "sandbox"), -) { - @Suppress("DestructuringDeclarationWithTooManyEntries") - override fun doBuildKeyFromSuffix(s3KeySuffix: String): SandboxStorageKey { - val (userId, typeName, filename) = s3KeySuffix.split(PATH_DELIMITER) - return SandboxStorageKey( - userId.toLong(), - SandboxStorageKeyType.valueOf(typeName), - filename, - ) - } - - override fun doBuildS3KeySuffix(key: SandboxStorageKey): String = - concatS3Key(key.userId.toString(), key.type.name, key.fileName) - - /** - * @param userId - * @param types - * @return list of keys in storage with requested [SandboxStorageKey.type] and [SandboxStorageKey.userId] - */ - fun list( - userId: Long, - vararg types: SandboxStorageKeyType - ): Flux = list().filter { - it.userId == userId && it.type in types - } -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorageKey.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorageKey.kt deleted file mode 100644 index fa607c7f2e..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorageKey.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.saveourtool.save.sandbox.storage - -/** - * @property userId - * @property type - * @property fileName - */ -data class SandboxStorageKey( - val userId: Long, - val type: SandboxStorageKeyType, - val fileName: String, -) { - companion object { - private const val DEBUG_INFO_FILE_NAME = "file_name.txt" - - /** - * create key for DebugInfoKey - * - * @param userId - * @return [SandboxStorageKey] with type [SandboxStorageKeyType.DEBUG_INFO] - */ - fun debugInfoKey( - userId: Long - ): SandboxStorageKey = SandboxStorageKey( - userId, - SandboxStorageKeyType.DEBUG_INFO, - DEBUG_INFO_FILE_NAME - ) - } -} diff --git a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorageKeyType.kt b/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorageKeyType.kt deleted file mode 100644 index 6f317aaf96..0000000000 --- a/save-sandbox/src/main/kotlin/com/saveourtool/save/sandbox/storage/SandboxStorageKeyType.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.saveourtool.save.sandbox.storage - -/** - * Type of sandbox files - */ -enum class SandboxStorageKeyType { - DEBUG_INFO, - FILE, - TEST, - ; -} diff --git a/save-sandbox/src/main/resources/META-INF/spring.factories b/save-sandbox/src/main/resources/META-INF/spring.factories deleted file mode 100644 index b1a3f50ce9..0000000000 --- a/save-sandbox/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1 +0,0 @@ -org.springframework.boot.env.EnvironmentPostProcessor=com.saveourtool.save.spring.postprocessor.DockerSecretsDatabaseProcessor \ No newline at end of file diff --git a/save-sandbox/src/main/resources/application-container-desktop.properties b/save-sandbox/src/main/resources/application-container-desktop.properties deleted file mode 100644 index a102c58f48..0000000000 --- a/save-sandbox/src/main/resources/application-container-desktop.properties +++ /dev/null @@ -1,3 +0,0 @@ -# suppress inspection "HttpUrlsUsage" -sandbox.agent-settings.sandbox-url=http://${COMPUTERNAME}.local:${server.port} -orchestrator.docker.host=npipe:////./pipe/docker_engine diff --git a/save-sandbox/src/main/resources/application-dev.properties b/save-sandbox/src/main/resources/application-dev.properties deleted file mode 100644 index d1b6ea6e54..0000000000 --- a/save-sandbox/src/main/resources/application-dev.properties +++ /dev/null @@ -1,9 +0,0 @@ -spring.datasource.url=jdbc:mysql://localhost:3306/save_sandbox -spring.datasource.username=root -spring.datasource.password=123 -sandbox.s3-storage.endpoint=http://localhost:9000 -sandbox.s3-storage.bucketName=cnb -sandbox.s3-storage.credentials.accessKeyId=admin -sandbox.s3-storage.credentials.secretAccessKey=adminadmin -sandbox.s3-storage.createBucketIfNotExists=true -orchestrator.agents-count=1 diff --git a/save-sandbox/src/main/resources/application-kafka.properties b/save-sandbox/src/main/resources/application-kafka.properties deleted file mode 100644 index f8e48bb156..0000000000 --- a/save-sandbox/src/main/resources/application-kafka.properties +++ /dev/null @@ -1 +0,0 @@ -spring.kafka.consumer.group-id=sandbox-local-group \ No newline at end of file diff --git a/save-sandbox/src/main/resources/application-minikube.properties b/save-sandbox/src/main/resources/application-minikube.properties deleted file mode 100644 index ff2cda41b7..0000000000 --- a/save-sandbox/src/main/resources/application-minikube.properties +++ /dev/null @@ -1,14 +0,0 @@ -# To get this port you should run this command: -# $ docker port minikube -# And find the following line: -# 8443/tcp -> 0.0.0.0:XXXX -# Here, XXXX is a requested port -orchestrator.kubernetes.apiServerUrl=https://127.0.0.1:61234 -orchestrator.kubernetes.serviceAccount=sandbox-sa -orchestrator.kubernetes.current-namespace=save-cloud -orchestrator.kubernetes.agent-namespace=save-agent -orchestrator.kubernetes.useGvisor=false -orchestrator.agent-settings.debug=true - -orchestrator.agent-settings.heartbeat-url=http://host.minikube.internal:5400/heartbeat -sandbox.agent-settings.sandbox-url=http://host.minikube.internal:5400 diff --git a/save-sandbox/src/main/resources/application-prod.properties b/save-sandbox/src/main/resources/application-prod.properties deleted file mode 100644 index 6bfdd3736a..0000000000 --- a/save-sandbox/src/main/resources/application-prod.properties +++ /dev/null @@ -1 +0,0 @@ -spring.datasource.url=jdbc:mysql://192.168.0.250:3306/save_sandbox diff --git a/save-sandbox/src/main/resources/application.properties b/save-sandbox/src/main/resources/application.properties deleted file mode 100644 index e58f754fdf..0000000000 --- a/save-sandbox/src/main/resources/application.properties +++ /dev/null @@ -1,19 +0,0 @@ -server.port=5400 -spring.liquibase.enabled=false -# suppress inspection "HttpUrlsUsage" -sandbox.agent-settings.sandbox-url=http://host.docker.internal:${server.port} -orchestrator.container-name-prefix=sandbox-execution- -orchestrator.agents-count=1 -spring.jpa.hibernate.use-new-id-generator-mappings=false -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect -spring.jpa.properties.hibernate.generate_statistics=true -spring.jpa.properties.hibernate.jdbc.fetch_size=100 -spring.jpa.properties.hibernate.jdbc.batch_size=100 -spring.jpa.properties.hibernate.order_inserts=true -spring.jpa.properties.hibernate.order_updates=true -logging.level.org.hibernate.engine.internal.StatisticalLoggingSessionEventListener=WARN -sandbox.s3-storage.endpoint=${s3-storage.endpoint} -sandbox.s3-storage.bucketName=${s3-storage.bucketName} -sandbox.s3-storage.prefix=cnb/sandbox -sandbox.s3-storage.credentials.accessKeyId=${s3-storage.credentials.accessKeyId} -sandbox.s3-storage.credentials.secretAccessKey=${s3-storage.credentials.secretAccessKey} diff --git a/save-sandbox/src/main/resources/bootstrap.yml b/save-sandbox/src/main/resources/bootstrap.yml deleted file mode 100644 index e0567bc53a..0000000000 --- a/save-sandbox/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,32 +0,0 @@ -spring: - cloud: - kubernetes: - enabled: false -kubernetes: - # Dependency `io.kubernetes:client-java-spring-integration` doesn't respect `kubernetes` profile, - # so some things need to be disabled manually. - informer: - enabled: false - manifests: - enabled: false ---- -spring: - config: - activate: - on-profile: kubernetes - cloud: - kubernetes: - enabled: true - config: - enabled: true - paths: /home/cnb/config/application.properties - secrets: - enabled: true - paths: - - ${DATABASE_SECRETS_PATH} - - ${S3_SECRETS_PATH} -kubernetes: - informer: - enabled: true - manifests: - enabled: true \ No newline at end of file diff --git a/save-sandbox/src/main/resources/logback.xml b/save-sandbox/src/main/resources/logback.xml deleted file mode 100644 index 0c67a06f91..0000000000 --- a/save-sandbox/src/main/resources/logback.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %level %logger{36} - %msg %ex{5}%n - - - - - - - - - \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 42b7a9b361..8755a9768e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -46,7 +46,6 @@ include("save-preprocessor") include("test-utils") include("save-api") include("save-api-cli") -include("save-sandbox") include("authentication-service") include("save-demo") include("save-demo-cpg")