Use new GithubAuth flow in GitOps plugin

This commit is contained in:
Raghunandan
2020-06-24 12:18:37 +02:00
committed by Fredrik Adelöw
parent c32a61afe8
commit a306bf2c27
8 changed files with 139 additions and 125 deletions
+22
View File
@@ -79,6 +79,14 @@ export interface ListClusterRequest {
gitHubToken: string;
}
export interface GithubUserInfoRequest {
accessToken: string;
}
export interface GithubUserInfoResponse {
login: string;
}
export class FetchError extends Error {
get name(): string {
return this.constructor.name;
@@ -100,6 +108,7 @@ export type GitOpsApi = {
cloneClusterFromTemplate(req: CloneFromTemplateRequest): Promise<any>;
applyProfiles(req: ApplyProfileRequest): Promise<any>;
listClusters(req: ListClusterRequest): Promise<ListClusterStatusesResponse>;
fetchUserInfo(req: GithubUserInfoRequest): Promise<GithubUserInfoResponse>;
};
export const gitOpsApiRef = createApiRef<GitOpsApi>({
@@ -116,6 +125,19 @@ export class GitOpsRestApi implements GitOpsApi {
return await resp.json();
}
async fetchUserInfo(
req: GithubUserInfoRequest,
): Promise<GithubUserInfoResponse> {
const resp = await fetch(`https://api.github.com/user`, {
method: 'get',
headers: new Headers({
Authorization: `token ${req.accessToken}`,
}),
});
if (!resp.ok) throw await FetchError.forResponse(resp);
return await resp.json();
}
async fetchLog(req: PollLogRequest): Promise<StatusResponse> {
return await this.fetch<StatusResponse>(`/api/cluster/run-status`, {
method: 'post',
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React, { FC } from 'react';
import React, { FC, useState } from 'react';
import {
Content,
ContentHeader,
@@ -25,32 +25,28 @@ import {
Progress,
HeaderLabel,
useApi,
githubAuthApiRef,
} from '@backstage/core';
import ClusterTable from '../ClusterTable/ClusterTable';
import { Button } from '@material-ui/core';
import { useAsync, useLocalStorage } from 'react-use';
import { useAsync } from 'react-use';
import { gitOpsApiRef, ListClusterStatusesResponse } from '../../api';
import { Alert } from '@material-ui/lab';
const ClusterList: FC<{}> = () => {
const [loginInfo] = useLocalStorage<{
token: string;
username: string;
name: string;
}>('githubLoginDetails', {
token: '',
username: '',
name: 'Guest',
});
const api = useApi(gitOpsApiRef);
const githubAuth = useApi(githubAuthApiRef);
const [githubUsername, setGithubUsername] = useState(String);
const { loading, error, value } = useAsync<ListClusterStatusesResponse>(
() => {
async () => {
const accessToken = await githubAuth.getAccessToken();
const userInfo = await api.fetchUserInfo({ accessToken });
setGithubUsername(userInfo.login);
return api.listClusters({
gitHubToken: loginInfo.token,
gitHubUser: loginInfo.username,
gitHubToken: accessToken,
gitHubUser: githubUsername,
});
},
);
@@ -73,9 +69,6 @@ const ClusterList: FC<{}> = () => {
Please make sure that you start GitOps-API backend on localhost port
3008 before using this plugin.
</Alert>
<Alert severity="info">
If you're Guest, please login via GitHub first.
</Alert>
</div>
</Content>
);
@@ -100,7 +93,7 @@ const ClusterList: FC<{}> = () => {
return (
<Page theme={pageTheme.home}>
<Header title="GitOps-managed Clusters">
<HeaderLabel label="Welcome" value={loginInfo.name} />
<HeaderLabel label="Welcome" value={githubUsername} />
</Header>
{content}
</Page>
@@ -24,21 +24,16 @@ import {
Progress,
HeaderLabel,
useApi,
githubAuthApiRef,
} from '@backstage/core';
import { Link } from '@material-ui/core';
import { useParams } from 'react-router-dom';
import { useLocalStorage } from 'react-use';
import { gitOpsApiRef, Status } from '../../api';
import { transformRunStatus } from '../ProfileCatalog';
const ClusterPage: FC<{}> = () => {
const params = useParams() as { owner: string; repo: string };
const [loginInfo] = useLocalStorage<{
token: string;
username: string;
name: string;
}>('githubLoginDetails');
const [pollingLog, setPollingLog] = useState(true);
const [runStatus, setRunStatus] = useState<Status[]>([]);
@@ -46,6 +41,9 @@ const ClusterPage: FC<{}> = () => {
const [showProgress, setShowProgress] = useState(true);
const api = useApi(gitOpsApiRef);
const githubAuth = useApi(githubAuthApiRef);
const [githubAccessToken, setGithubAccessToken] = useState(String);
const [githubUsername, setGithubUsername] = useState(String);
const columns = [
{ field: 'status', title: 'Status' },
@@ -53,11 +51,22 @@ const ClusterPage: FC<{}> = () => {
];
useEffect(() => {
const fetchGithubUserInfo = async () => {
const accessToken = await githubAuth.getAccessToken();
const userInfo = await api.fetchUserInfo({ accessToken });
setGithubAccessToken(accessToken);
setGithubUsername(userInfo.login);
};
if (!githubAccessToken || !githubUsername) {
fetchGithubUserInfo();
}
if (pollingLog) {
const interval = setInterval(async () => {
const resp = await api.fetchLog({
gitHubToken: loginInfo.token,
gitHubUser: loginInfo.username,
gitHubToken: githubAccessToken,
gitHubUser: githubUsername,
targetOrg: params.owner,
targetRepo: params.repo,
});
@@ -72,12 +81,12 @@ const ClusterPage: FC<{}> = () => {
return () => clearInterval(interval);
}
return () => {};
}, [pollingLog, api, loginInfo, params]);
}, [pollingLog, api, params, githubAuth, githubAccessToken, githubUsername]);
return (
<Page theme={pageTheme.home}>
<Header title={`Cluster ${params.owner}/${params.repo}`}>
<HeaderLabel label="Welcome" value={loginInfo.name} />
<HeaderLabel label="Welcome" value={githubUsername} />
</Header>
<Content>
<Progress hidden={!showProgress} />
@@ -35,6 +35,7 @@ import {
StatusPending,
StatusAborted,
useApi,
githubAuthApiRef,
} from '@backstage/core';
import { TextField, List, ListItem, Link } from '@material-ui/core';
@@ -111,17 +112,12 @@ const ProfileCatalog: FC<{}> = () => {
},
]);
const [loginInfo] = useLocalStorage('githubLoginDetails', {
name: 'Guest',
username: '',
token: '',
});
const [templateRepo] = useLocalStorage<string>('gitops-template-repo');
const [gitopsProfiles] = useLocalStorage<string[]>('gitops-profiles');
const [showProgress, setShowProgress] = useState(false);
const [pollingLog, setPollingLog] = useState(false);
const [gitHubOrg, setGitHubOrg] = useState(loginInfo.username);
const [gitHubOrg, setGitHubOrg] = useState(String);
const [gitHubRepo, setGitHubRepo] = useState('new-cluster');
const [awsAccessKeyId, setAwsAccessKeyId] = useState(String);
const [awsSecretAccessKey, setAwsSecretAccessKey] = useState(String);
@@ -129,13 +125,28 @@ const ProfileCatalog: FC<{}> = () => {
const [runLink, setRunLink] = useState<string>('');
const api = useApi(gitOpsApiRef);
const githubAuth = useApi(githubAuthApiRef);
const [githubAccessToken, setGithubAccessToken] = useState(String);
const [githubUsername, setGithubUsername] = useState(String);
useEffect(() => {
const fetchGithubUserInfo = async () => {
const accessToken = await githubAuth.getAccessToken();
const userInfo = await api.fetchUserInfo({ accessToken });
setGithubAccessToken(accessToken);
setGithubUsername(userInfo.login);
setGitHubOrg(userInfo.login);
};
if (!githubAccessToken || !githubUsername) {
fetchGithubUserInfo();
}
if (pollingLog) {
const interval = setInterval(async () => {
const resp = await api.fetchLog({
gitHubToken: loginInfo.token,
gitHubUser: loginInfo.username,
gitHubToken: githubAccessToken,
gitHubUser: githubUsername,
targetOrg: gitHubOrg,
targetRepo: gitHubRepo,
});
@@ -150,7 +161,15 @@ const ProfileCatalog: FC<{}> = () => {
return () => clearInterval(interval);
}
return () => {};
}, [pollingLog, api, gitHubOrg, gitHubRepo, loginInfo]);
}, [
pollingLog,
api,
gitHubOrg,
gitHubRepo,
githubAuth,
githubAccessToken,
githubUsername,
]);
const showFailureMessage = (msg: string) => {
setRunStatus(
@@ -182,8 +201,8 @@ const ProfileCatalog: FC<{}> = () => {
const cloneResponse = await api.cloneClusterFromTemplate({
templateRepository: templateRepo,
gitHubToken: loginInfo.token,
gitHubUser: loginInfo.username,
gitHubToken: githubAccessToken,
gitHubUser: githubUsername,
targetOrg: gitHubOrg,
targetRepo: gitHubRepo,
secrets: {
@@ -200,8 +219,8 @@ const ProfileCatalog: FC<{}> = () => {
}
const applyProfileResp = await api.applyProfiles({
gitHubToken: loginInfo.token,
gitHubUser: loginInfo.username,
gitHubToken: githubAccessToken,
gitHubUser: githubUsername,
targetOrg: gitHubOrg,
targetRepo: gitHubRepo,
profiles: gitopsProfiles,
@@ -215,8 +234,8 @@ const ProfileCatalog: FC<{}> = () => {
}
const clusterStateResp = await api.changeClusterState({
gitHubToken: loginInfo.token,
gitHubUser: loginInfo.username,
gitHubToken: githubAccessToken,
gitHubUser: githubUsername,
targetOrg: gitHubOrg,
targetRepo: gitHubRepo,
clusterState: 'present',
@@ -244,7 +263,7 @@ const ProfileCatalog: FC<{}> = () => {
title="Create GitOps-managed Cluster"
subtitle="Kubernetes cluster with ready-to-use profiles"
>
<HeaderLabel label="Welcome" value={loginInfo.name} />
<HeaderLabel label="Welcome" value={githubUsername} />
</Header>
<Content>
<ContentHeader title="Create Cluster">
+8 -3
View File
@@ -18,12 +18,17 @@ import { createPlugin } from '@backstage/core';
import ProfileCatalog from './components/ProfileCatalog';
import ClusterPage from './components/ClusterPage';
import ClusterList from './components/ClusterList';
import {
gitOpsClusterListRoute,
gitOpsClusterDetailsRoute,
gitOpsClusterCreateRoute,
} from './routes';
export const plugin = createPlugin({
id: 'gitops-profiles',
register({ router }) {
router.registerRoute('/gitops-clusters', ClusterList);
router.registerRoute('/gitops-cluster/:owner/:repo', ClusterPage);
router.registerRoute('/gitops-cluster-create', ProfileCatalog);
router.addRoute(gitOpsClusterListRoute, ClusterList);
router.addRoute(gitOpsClusterDetailsRoute, ClusterPage);
router.addRoute(gitOpsClusterCreateRoute, ProfileCatalog);
},
});
+37
View File
@@ -0,0 +1,37 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createRouteRef } from '@backstage/core';
const NoIcon = () => null;
export const gitOpsClusterListRoute = createRouteRef({
icon: NoIcon,
path: '/gitops-clusters',
title: 'GitOps Clusters',
});
export const gitOpsClusterDetailsRoute = createRouteRef({
icon: NoIcon,
path: '/gitops-cluster/:owner/:repo',
title: 'GitOps Cluster details',
});
export const gitOpsClusterCreateRoute = createRouteRef({
icon: NoIcon,
path: '/gitops-cluster-create',
title: 'GitOps Cluster create',
});