Skip to content

Commit

Permalink
Add custom path support (#890)
Browse files Browse the repository at this point in the history
* Revert Makefile

* Fix test

* Fix Tests

* Update yarn config
  • Loading branch information
migmartri authored and prydonius committed Dec 20, 2018
1 parent 8dab70c commit a6f3dc5
Show file tree
Hide file tree
Showing 24 changed files with 50 additions and 36 deletions.
9 changes: 9 additions & 0 deletions chart/kubeapps/templates/dashboard-config.yaml
Expand Up @@ -17,6 +17,15 @@ data:
gzip_static on;
location / {
# Support for ingress prefixes maintaining compatibility with the default /
# 1 - Exactly two fragment URLs for files existing inside of the public/ dir
# i.e /[prefix]/config.json => /config.json
rewrite ^/[^/]+/([^/]+)$ /$1 break;
# 2 - Any static files bundled by webpack referenced by 3 or more URL segments
# i.e /[prefix]/static/main.js => static/main.js
rewrite ^/[^/]+/static/(.*) /static/$1 break;
try_files $uri /index.html;
}
}
Expand Down
8 changes: 5 additions & 3 deletions chart/kubeapps/templates/kubeapps-frontend-config.yaml
Expand Up @@ -29,7 +29,9 @@ data:
return 200 "healthy\n";
}
location /api/kube {
# Using regexp match instead of prefix one because the application can be
# deployed under a specific path i.e /kubeapps
location ~* /api/kube {
rewrite /api/kube/(.*) /$1 break;
rewrite /api/kube / break;
proxy_pass https://kubernetes.default;
Expand All @@ -46,13 +48,13 @@ data:
proxy_read_timeout 1h;
}
location /api/chartsvc {
location ~* /api/chartsvc {
rewrite /api/chartsvc/(.*) /$1 break;
rewrite /api/chartsvc / break;
proxy_pass http://{{ template "kubeapps.chartsvc.fullname" . }}:{{ .Values.chartsvc.service.port }};
}
location /api/tiller-deploy {
location ~* /api/tiller-deploy {
# Keep the connection open with the API server even if idle (the default is 60 seconds)
# Setting it to 10 minutes which should be enough for our current use case of deploying/upgrading/deleting apps
proxy_read_timeout 10m;
Expand Down
1 change: 1 addition & 0 deletions dashboard/package.json
Expand Up @@ -2,6 +2,7 @@
"name": "dashboard",
"version": "0.1.0",
"private": true,
"homepage": "./",
"dependencies": {
"@types/js-yaml": "^3.10.1",
"@types/json-schema": "^6.0.1",
Expand Down
10 changes: 5 additions & 5 deletions dashboard/src/actions/charts.test.tsx
Expand Up @@ -38,7 +38,7 @@ describe("fetchCharts", () => {
];
await store.dispatch(actions.charts.fetchCharts("foo"));
expect(store.getActions()).toEqual(expectedActions);
expect(fetchMock.mock.calls[0][0]).toBe("/api/chartsvc/v1/charts/foo");
expect(fetchMock.mock.calls[0][0]).toBe("api/chartsvc/v1/charts/foo");
});

it("returns a 404 error", async () => {
Expand Down Expand Up @@ -89,7 +89,7 @@ describe("fetchChartVersions", () => {
];
await store.dispatch(actions.charts.fetchChartVersions("foo"));
expect(store.getActions()).toEqual(expectedActions);
expect(fetchMock.mock.calls[0][0]).toBe("/api/chartsvc/v1/charts/foo/versions");
expect(fetchMock.mock.calls[0][0]).toBe("api/chartsvc/v1/charts/foo/versions");
});
});

Expand All @@ -102,7 +102,7 @@ describe("getChartVersion", () => {
];
await store.dispatch(actions.charts.getChartVersion("foo", "1.0.0"));
expect(store.getActions()).toEqual(expectedActions);
expect(fetchMock.mock.calls[0][0]).toBe("/api/chartsvc/v1/charts/foo/versions/1.0.0");
expect(fetchMock.mock.calls[0][0]).toBe("api/chartsvc/v1/charts/foo/versions/1.0.0");
});
});

Expand All @@ -116,7 +116,7 @@ describe("fetchChartVersionsAndSelectVersion", () => {
];
await store.dispatch(actions.charts.fetchChartVersionsAndSelectVersion("foo", "1.0.0"));
expect(store.getActions()).toEqual(expectedActions);
expect(fetchMock.mock.calls[0][0]).toBe("/api/chartsvc/v1/charts/foo/versions");
expect(fetchMock.mock.calls[0][0]).toBe("api/chartsvc/v1/charts/foo/versions");
});

it("returns a not found error", async () => {
Expand All @@ -137,6 +137,6 @@ describe("fetchChartVersionsAndSelectVersion", () => {
window.fetch = fetchMock;
await store.dispatch(actions.charts.fetchChartVersionsAndSelectVersion("foo", "1.0.0"));
expect(store.getActions()).toEqual(expectedActions);
expect(fetchMock.mock.calls[0][0]).toBe("/api/chartsvc/v1/charts/foo/versions");
expect(fetchMock.mock.calls[0][0]).toBe("api/chartsvc/v1/charts/foo/versions");
});
});
4 changes: 2 additions & 2 deletions dashboard/src/actions/kube.test.tsx
Expand Up @@ -35,12 +35,12 @@ describe("get resources", () => {
const expectedActions = [
{
type: getType(actions.kube.requestResource),
payload: "/api/kube/api/v1/namespaces/default/pods/foo",
payload: "api/kube/api/v1/namespaces/default/pods/foo",
},
{
type: getType(actions.kube.receiveResource),
payload: {
key: "/api/kube/api/v1/namespaces/default/pods/foo",
key: "api/kube/api/v1/namespaces/default/pods/foo",
resource: [],
},
},
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/components/Catalog/CatalogItem.tsx
Expand Up @@ -25,7 +25,7 @@ function trimDescription(desc: string): string {
const CatalogItem: React.SFC<ICatalogItemProps> = props => {
const { chart } = props;
const { icon, name, repo } = chart.attributes;
const iconSrc = icon ? `/api/chartsvc/${icon}` : placeholder;
const iconSrc = icon ? `api/chartsvc/${icon}` : placeholder;
const latestAppVersion = chart.relationships.latestChartVersion.data.app_version;
const repoTag = (
<Link className="ListItem__content__info_tag_link" to={`/catalog/${repo.name}`}>
Expand Down
Expand Up @@ -9,7 +9,7 @@ exports[`should render an item 1`] = `
</div>
}
icon="/api/chartsvc/icon.png"
icon="api/chartsvc/icon.png"
info="1.0.0"
key="[object Object]/foo"
link="/charts/foo"
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/components/ChartIcon/ChartIcon.tsx
Expand Up @@ -10,7 +10,7 @@ interface IChartIconProps {
class ChartIcon extends React.Component<IChartIconProps> {
public render() {
const { icon } = this.props;
const iconSrc = icon ? `/api/chartsvc/${icon}` : placeholder;
const iconSrc = icon ? `api/chartsvc/${icon}` : placeholder;

return (
<div className="ChartIcon">
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/shared/App.ts
Expand Up @@ -3,7 +3,7 @@ import { axios } from "./Auth";
import { hapi } from "./hapi/release";
import { IAppOverview, IChartVersion } from "./types";

export const TILLER_PROXY_ROOT_URL = "/api/tiller-deploy/v1";
export const TILLER_PROXY_ROOT_URL = "api/tiller-deploy/v1";

export class App {
public static getResourceURL(namespace?: string, name?: string, query?: string) {
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/shared/AppRepository.ts
Expand Up @@ -34,7 +34,7 @@ export class AppRepository {
return data;
}

private static APIBase: string = "/api/kube";
private static APIBase: string = "api/kube";
private static APIEndpoint: string = `${AppRepository.APIBase}/apis/kubeapps.com/v1alpha1`;
private static getResourceLink(namespace?: string): string {
return `${AppRepository.APIEndpoint}/${
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/shared/Auth.ts
Expand Up @@ -36,7 +36,7 @@ export class Auth {
// Throws an error if the token is invalid
public static async validateToken(token: string) {
try {
await Axios.get("/api/kube/", { headers: { Authorization: `Bearer ${token}` } });
await Axios.get("api/kube/", { headers: { Authorization: `Bearer ${token}` } });
} catch (e) {
const res = e.response as AxiosResponse;
if (res.status === 401) {
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/shared/Chart.ts
Expand Up @@ -23,5 +23,5 @@ export default class Chart {
return true;
}

private static APIEndpoint: string = "/api/chartsvc/v1";
private static APIEndpoint: string = "api/chartsvc/v1";
}
2 changes: 1 addition & 1 deletion dashboard/src/shared/ClusterServiceClass.ts
Expand Up @@ -44,7 +44,7 @@ export class ClusterServiceClass {
}

private static getLink(namespace?: string, name?: string): string {
return `/api/kube/apis/servicecatalog.k8s.io/v1beta1${
return `api/kube/apis/servicecatalog.k8s.io/v1beta1${
namespace ? `/namespaces/${namespace}` : ""
}/clusterserviceclasses${name ? `/${name}` : ""}`;
}
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/shared/Config.test.ts
Expand Up @@ -12,7 +12,7 @@ describe("Config", () => {

defaultJSON = require("../../public/config.json");

moxios.stubRequest("/config.json", { status: 200, response: defaultJSON });
moxios.stubRequest("config.json", { status: 200, response: defaultJSON });
});

afterEach(() => {
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/shared/Config.ts
Expand Up @@ -23,5 +23,5 @@ export default class Config {
return data;
}

private static APIEndpoint: string = "/config.json";
private static APIEndpoint: string = "config.json";
}
2 changes: 1 addition & 1 deletion dashboard/src/shared/Kube.ts
@@ -1,7 +1,7 @@
import { axios } from "./Auth";
import { IResource } from "./types";

export const KUBE_ROOT_URL = "/api/kube";
export const KUBE_ROOT_URL = "api/kube";

export class Kube {
public static getResourceURL(
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/shared/Namespace.ts
Expand Up @@ -8,7 +8,7 @@ export default class Namespace {
return data;
}

private static APIBase: string = "/api/kube";
private static APIBase: string = "api/kube";
private static APIEndpoint: string = `${Namespace.APIBase}/api/v1/namespaces`;
}

Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/shared/Secret.ts
Expand Up @@ -41,6 +41,6 @@ export default class Secret {
}

private static getLink(namespace: string, name?: string): string {
return `/api/kube/api/v1/namespaces/${namespace}/secrets${name ? `/${name}` : ""}`;
return `api/kube/api/v1/namespaces/${namespace}/secrets${name ? `/${name}` : ""}`;
}
}
4 changes: 2 additions & 2 deletions dashboard/src/shared/ServiceBinding.ts
Expand Up @@ -101,12 +101,12 @@ export class ServiceBinding {
}

private static getLink(namespace?: string, name?: string): string {
return `/api/kube/apis/servicecatalog.k8s.io/v1beta1${
return `api/kube/apis/servicecatalog.k8s.io/v1beta1${
namespace ? `/namespaces/${namespace}` : ""
}/servicebindings${name ? `/${name}` : ""}`;
}

private static secretEndpoint(namespace: string = definedNamespaces.default): string {
return `/api/kube/api/v1/namespaces/${namespace}/secrets/`;
return `api/kube/api/v1/namespaces/${namespace}/secrets/`;
}
}
4 changes: 2 additions & 2 deletions dashboard/src/shared/ServiceCatalog.ts
Expand Up @@ -19,7 +19,7 @@ export class ServiceCatalog {
}

public static async deprovisionInstance(instance: IServiceInstance) {
const { data } = await axios.delete("/api/kube" + instance.metadata.selfLink);
const { data } = await axios.delete("api/kube" + instance.metadata.selfLink);
return data;
}

Expand Down Expand Up @@ -56,7 +56,7 @@ export class ServiceCatalog {
return json.items;
}

private static endpoint: string = "/api/kube/apis/servicecatalog.k8s.io/v1beta1";
private static endpoint: string = "api/kube/apis/servicecatalog.k8s.io/v1beta1";
}
export interface IK8sApiListResponse<T> {
kind: string;
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/shared/ServiceInstance.ts
Expand Up @@ -65,7 +65,7 @@ export class ServiceInstance {
}

private static getLink(namespace?: string, name?: string): string {
return `/api/kube/apis/servicecatalog.k8s.io/v1beta1${
return `api/kube/apis/servicecatalog.k8s.io/v1beta1${
namespace ? `/namespaces/${namespace}` : ""
}/serviceinstances${name ? `/${name}` : ""}`;
}
Expand Down
4 changes: 2 additions & 2 deletions dashboard/src/shared/WebSocketHelper.ts
Expand Up @@ -4,9 +4,9 @@ export default class WebSocketHelper {

// Use WebSockets Secure if using HTTPS and WebSockets if not
if (location.protocol === "https:") {
apiBase = `wss://${window.location.host}/api/kube`;
apiBase = `wss://${window.location.host}${window.location.pathname}api/kube`;
} else {
apiBase = `ws://${window.location.host}/api/kube`;
apiBase = `ws://${window.location.host}${window.location.pathname}api/kube`;
}
return apiBase;
}
Expand Down
8 changes: 4 additions & 4 deletions dashboard/src/shared/url.ts
Expand Up @@ -13,13 +13,13 @@ export const app = {

export const api = {
apprepostories: {
base: "/api/kube/apis/kubeapps.com/v1alpha1",
base: "api/kube/apis/kubeapps.com/v1alpha1",
create: (namespace = definedNamespaces.default) =>
`${api.apprepostories.base}/namespaces/${namespace}/apprepositories`,
},

charts: {
base: "/api/chartsvc/v1",
base: "api/chartsvc/v1",
get: (id: string) => `${api.charts.base}/charts/${id}`,
getReadme: (id: string, version: string) =>
`${api.charts.base}/assets/${id}/versions/${version}/README.md`,
Expand All @@ -32,13 +32,13 @@ export const api = {
},

serviceinstances: {
base: "/api/kube/apis/servicecatalog.k8s.io/v1beta1",
base: "api/kube/apis/servicecatalog.k8s.io/v1beta1",
create: (namespace = definedNamespaces.default) =>
`${api.serviceinstances.base}/namespaces/${namespace}/serviceinstances`,
},

clusterservicebrokers: {
base: "/api/kube/apis/servicecatalog.k8s.io/v1beta1",
base: "api/kube/apis/servicecatalog.k8s.io/v1beta1",
sync: (broker: IServiceBroker) =>
`${api.clusterservicebrokers.base}/clusterservicebrokers/${broker.metadata.name}`,
},
Expand Down
6 changes: 4 additions & 2 deletions dashboard/src/store/index.ts
@@ -1,12 +1,14 @@
import { connectRouter, routerMiddleware } from "connected-react-router";
import createHistory from "history/createBrowserHistory";
import { createHashHistory } from "history";
import { applyMiddleware, createStore } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import thunkMiddleware from "redux-thunk";

import rootReducer from "../reducers";

export const history = createHistory();
// Use Hash based routing to support deploying Kubeapps in arbitrary URL subpaths
export const history = createHashHistory();

export default createStore(
connectRouter(history)(rootReducer), // add router state to reducer
composeWithDevTools(
Expand Down

0 comments on commit a6f3dc5

Please sign in to comment.