Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Serve SwaggerUI #6989

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/check-generated-files.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ jobs:
- name: Generate static files for UI
run: make ui-static

- name: Copy embedded files to Go sources
run: make prebuild

- name: Verify Changed files
uses: tj-actions/verify-changed-files@7f1b21ceb7ef533b97b46e89e2f882ee5cb17ae0
id: verify-changed-files

- name: Some files have changed
if: steps.verify-changed-files.outputs.files_changed == 'true'
run: |
echo "::error Changed files: ${{ steps.verify-changed-files.outputs.changed_files }} -- Please regenerate with make ui-static"
echo "::error Changed files: ${{ steps.verify-changed-files.outputs.changed_files }} -- Please regenerate with make ui-static / make prebuild"
exit 1
14 changes: 11 additions & 3 deletions Makefile
rm3l marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,20 @@ ui-static: ## build static files for UI to be served by embedded API server
-t docker.io/library/node:18 \
/bin/sh -c "cd /local && (cd ui && npm install && npm run build) && rm -rf pkg/apiserver-impl/ui/* && mv ui/dist/devfile-builder/* pkg/apiserver-impl/ui/"

.PHONY: prebuild
prebuild: ## Step to place go embedded files into Go sources before to build the go executable
cp ododevapispec.yaml pkg/apiserver-impl/swagger-ui/swagger.yaml
rm3l marked this conversation as resolved.
Show resolved Hide resolved

.PHONY: bin
bin: ## build the odo binary
bin: prebuild ## build the odo binary
go build ${BUILD_FLAGS} cmd/odo/odo.go

.PHONY: release-bin
release-bin: ## build the odo binary
release-bin: prebuild ## build the odo binary
go build ${RELEASE_BUILD_FLAGS} cmd/odo/odo.go

.PHONY: install
install:
install: prebuild
go install ${BUILD_FLAGS} ./cmd/odo/

.PHONY: validate
Expand Down Expand Up @@ -266,3 +270,7 @@ generate-apifront: ## Generate OpenAPISpec library based on ododevapispec.yaml i

.PHONY: generate-api
generate-api: generate-apiserver generate-apifront ## Generate code based on ododevapispec.yaml

.PHONY: copy-swagger-ui
copy-swagger-ui:
./scripts/copy-swagger-ui.sh
15 changes: 15 additions & 0 deletions docs/website/docs/user-guides/advanced/api-serverv.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: API server
sidebar_position: 10
tags: ["api"]
slug: api-server
---

# API Server

An `odo dev` session starts an API server, generally available on `http://localhost:20000/api/v1/`
(the port number can change depending on availability of ports),
which can be used to get information from the Dev session and to send commands to the session.

The developer documentation of the API is available at `http://localhost:20000/swagger-ui/`
(the port can change and the `odo dev` command displays it when it starts).
44 changes: 44 additions & 0 deletions ododevapispec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,8 @@ paths:

/devstate/devfile:
put:
tags:
- devstate
description: Updates the complete Devfile content
requestBody:
content:
Expand Down Expand Up @@ -348,6 +350,8 @@ paths:
message: "Error updating the Devfile content"

get:
tags:
- devstate
description: Get the complete Devfile content
responses:
'200':
Expand Down Expand Up @@ -395,6 +399,8 @@ paths:
message: "Error getting the Devfile content"

delete:
tags:
- devstate
description: Clear the Devfile content
responses:
'200':
Expand Down Expand Up @@ -443,6 +449,8 @@ paths:

/devstate/metadata:
put:
tags:
- devstate
description: Updates the metadata for the Devfile
requestBody:
content:
Expand Down Expand Up @@ -496,6 +504,8 @@ paths:

/devstate/container:
post:
tags:
- devstate
description: Add a new container to the Devfile
requestBody:
content:
Expand Down Expand Up @@ -580,6 +590,8 @@ paths:

/devstate/container/{containerName}:
delete:
tags:
- devstate
description: "Delete a container from the Devfile"
parameters:
- name: containerName
Expand Down Expand Up @@ -608,6 +620,8 @@ paths:

/devstate/image:
post:
tags:
- devstate
description: Add a new image to the Devfile
requestBody:
content:
Expand Down Expand Up @@ -678,6 +692,8 @@ paths:

/devstate/image/{imageName}:
delete:
tags:
- devstate
description: "Delete an image from the Devfile"
parameters:
- name: imageName
Expand Down Expand Up @@ -706,6 +722,8 @@ paths:

/devstate/resource:
post:
tags:
- devstate
description: Add a new Kubernetes resource to the Devfile
requestBody:
content:
Expand Down Expand Up @@ -767,6 +785,8 @@ paths:

/devstate/resource/{resourceName}:
delete:
tags:
- devstate
description: "Delete a resource from the Devfile"
parameters:
- name: resourceName
Expand Down Expand Up @@ -795,6 +815,8 @@ paths:

/devstate/applyCommand:
post:
tags:
- devstate
description: Add a new Apply Command to the Devfile
requestBody:
content:
Expand Down Expand Up @@ -854,6 +876,8 @@ paths:

/devstate/command/{commandName}:
delete:
tags:
- devstate
description: "Delete a command from the Devfile"
parameters:
- name: commandName
Expand Down Expand Up @@ -882,6 +906,8 @@ paths:

/devstate/command/{commandName}/move:
post:
tags:
- devstate
description: "Move a command"
parameters:
- name: commandName
Expand Down Expand Up @@ -928,6 +954,8 @@ paths:

/devstate/command/{commandName}/setDefault:
post:
tags:
- devstate
description: "Set a command as default command for a group"
parameters:
- name: commandName
Expand Down Expand Up @@ -965,6 +993,8 @@ paths:

/devstate/command/{commandName}/unsetDefault:
post:
tags:
- devstate
description: "Unset a command as default command for its group"
parameters:
- name: commandName
Expand Down Expand Up @@ -993,6 +1023,8 @@ paths:

/devstate/compositeCommand:
post:
tags:
- devstate
description: Add a new Composite Command to the Devfile
requestBody:
content:
Expand Down Expand Up @@ -1057,6 +1089,8 @@ paths:

/devstate/execCommand:
post:
tags:
- devstate
description: Add a new Exec Command to the Devfile
requestBody:
content:
Expand Down Expand Up @@ -1122,6 +1156,8 @@ paths:

/devstate/events:
put:
tags:
- devstate
description: Updates the Events for the Devfile
requestBody:
content:
Expand Down Expand Up @@ -1184,6 +1220,8 @@ paths:

/devstate/chart:
get:
tags:
- devstate
description: Get chart representing the Devfile cycle in mermaid format
responses:
'200':
Expand All @@ -1201,6 +1239,8 @@ paths:

/devstate/quantityValid:
post:
tags:
- devstate
description: Check if a quantity is valid
requestBody:
content:
Expand Down Expand Up @@ -1524,3 +1564,7 @@ components:
supportUrl:
type: string

tags:
- name: default
- name: devstate
description: Devfile State manager, used by the UI
13 changes: 13 additions & 0 deletions pkg/apiserver-impl/starterserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ import (
//go:embed ui/*
var staticFiles embed.FS

// swagger UI files are from https://github.com/swagger-api/swagger-ui/tree/master/dist

//go:embed swagger-ui/*
var swaggerFiles embed.FS

type ApiServer struct {
PushWatcher <-chan struct{}
}
Expand Down Expand Up @@ -57,6 +62,14 @@ func StartServer(

router := openapi.NewRouter(sseNotifier, defaultApiController)

fSysSwagger, err := fs.Sub(swaggerFiles, "swagger-ui")
if err != nil {
// Assertion, error can only happen if the path "swagger-ui" is not valid
panic(err)
}
swaggerServer := http.FileServer(http.FS(fSysSwagger))
router.PathPrefix("/swagger-ui/").Handler(http.StripPrefix("/swagger-ui/", swaggerServer))

fSys, err := fs.Sub(staticFiles, "ui")
if err != nil {
// Assertion, error can only happen if the path "ui" is not valid
Expand Down
Binary file added pkg/apiserver-impl/swagger-ui/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added pkg/apiserver-impl/swagger-ui/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions pkg/apiserver-impl/swagger-ui/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}

*,
*:before,
*:after {
box-sizing: inherit;
}

body {
margin: 0;
background: #fafafa;
}
19 changes: 19 additions & 0 deletions pkg/apiserver-impl/swagger-ui/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="index.css" />
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
</head>

<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script src="./swagger-initializer.js" charset="UTF-8"> </script>
</body>
</html>
79 changes: 79 additions & 0 deletions pkg/apiserver-impl/swagger-ui/oauth2-redirect.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<!doctype html>
<html lang="en-US">
<head>
<title>Swagger UI: OAuth2 Redirect</title>
</head>
<body>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;

if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1).replace('?', '&');
} else {
qp = location.search.substring(1);
}

arr = qp.split("&");
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value);
}
) : {};

isValid = qp.state === sentState;

if ((
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
});
}

if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg;
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}

oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}

if (document.readyState !== 'loading') {
run();
} else {
document.addEventListener('DOMContentLoaded', function () {
run();
});
}
</script>
</body>
</html>
Loading