diff --git a/plugins/nomad/package.json b/plugins/nomad/package.json
index e195a2fbe0..79a0fb0607 100644
--- a/plugins/nomad/package.json
+++ b/plugins/nomad/package.json
@@ -23,8 +23,10 @@
},
"dependencies": {
"@backstage/catalog-model": "workspace:^",
+ "@backstage/config": "workspace:^",
"@backstage/core-components": "workspace:^",
"@backstage/core-plugin-api": "workspace:^",
+ "@backstage/plugin-catalog-react": "workspace:^",
"@backstage/theme": "workspace:^",
"@material-ui/core": "^4.9.13",
"@material-ui/icons": "^4.9.1",
@@ -32,7 +34,8 @@
"react-use": "^17.2.4"
},
"peerDependencies": {
- "react": "^16.13.1 || ^17.0.0"
+ "react": "^16.13.1 || ^17.0.0",
+ "react-router-dom": "*"
},
"devDependencies": {
"@backstage/cli": "workspace:^",
diff --git a/plugins/nomad/src/components/Router.tsx b/plugins/nomad/src/Router.tsx
similarity index 63%
rename from plugins/nomad/src/components/Router.tsx
rename to plugins/nomad/src/Router.tsx
index c6b4ac47e8..d65fda777a 100644
--- a/plugins/nomad/src/components/Router.tsx
+++ b/plugins/nomad/src/Router.tsx
@@ -14,10 +14,12 @@
* limitations under the License.
*/
+import React from 'react';
import { Entity } from '@backstage/catalog-model';
-
-/** @public */
-export const NOMAD_JOB_ANNOTATION = 'nomad.io/job';
+import { useEntity } from '@backstage/plugin-catalog-react';
+import { MissingAnnotationEmptyState } from '@backstage/core-components';
+import { Route, Routes } from 'react-router-dom';
+import { GroupListForEntity } from './components/GroupList/GroupListForEntity';
/** @public */
export const NOMAD_GROUP_ANNOTATION = 'nomad.io/group';
@@ -27,6 +29,20 @@ export const NOMAD_TASK_ANNOTATION = 'nomad.io/task';
/** @public */
export const isNomadAvailable = (entity: Entity) =>
- Boolean(entity.metadata.annotations?.[NOMAD_JOB_ANNOTATION]) ||
Boolean(entity.metadata.annotations?.[NOMAD_GROUP_ANNOTATION]) ||
Boolean(entity.metadata.annotations?.[NOMAD_TASK_ANNOTATION]);
+
+/** @public */
+export const EmbeddedRouter = () => {
+ const { entity } = useEntity();
+
+ if (!isNomadAvailable(entity)) {
+ return ;
+ }
+
+ return (
+
+ } />
+
+ );
+};
diff --git a/plugins/nomad/src/api.ts b/plugins/nomad/src/api.ts
new file mode 100644
index 0000000000..ca5113524b
--- /dev/null
+++ b/plugins/nomad/src/api.ts
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2020 The Backstage Authors
+ *
+ * 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 { Config } from '@backstage/config';
+import { createApiRef } from '@backstage/core-plugin-api';
+
+/** @public */
+export const nomadApiRef = createApiRef({
+ id: 'plugin.nomad.service',
+});
+
+/** @public */
+export type NomadApi = {
+ /**
+ * listAllocations is for listing all allocations matching some part of 'prefix'.
+ *
+ * See: https://developer.hashicorp.com/nomad/api-docs/allocations#list-allocations
+ */
+ listAllocations: (
+ options: ListAllocationsRequest,
+ ) => Promise;
+};
+
+/** @public */
+export interface ListAllocationsRequest {
+ namespace?: string;
+ filter?: string;
+}
+
+/** @public */
+export interface ListAllocationsResponse {
+ allocations: Allocation[];
+}
+
+/** @public */
+export interface Allocation {
+ id: string;
+ clientStatus: string;
+ createTime: number;
+ namespace: string;
+ name: string;
+ modifyTime: number;
+ nodeID: string;
+ taskGroup: string;
+}
+
+/** @public */
+export interface DeploymentStatus {
+ healthy: boolean;
+ timestamp: string;
+}
+
+/** @public */
+export class NomadHttpApi implements NomadApi {
+ static fromConfig(config: Config) {
+ return new NomadHttpApi(
+ config.getOptionalString('nomad.nomadAddr'),
+ config.getOptionalString('nomad.nomadRegion'),
+ config.getOptionalString('nomad.nomadNamespace'),
+ config.getOptionalString('nomad.nomadToken'),
+ );
+ }
+
+ constructor(
+ private nomadAddr?: string,
+ private nomadRegion?: string,
+ private nomadNamespace?: string,
+ private nomadToken?: string,
+ ) {}
+
+ async listAllocations(
+ options: ListAllocationsRequest,
+ ): Promise {
+ return Promise.resolve({
+ allocations: [],
+ });
+ }
+}
diff --git a/plugins/nomad/src/components/GroupList/GroupListForEntity.tsx b/plugins/nomad/src/components/GroupList/GroupListForEntity.tsx
new file mode 100644
index 0000000000..101d894a81
--- /dev/null
+++ b/plugins/nomad/src/components/GroupList/GroupListForEntity.tsx
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2020 The Backstage Authors
+ *
+ * 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 { Table } from '@backstage/core-components';
+import React from 'react';
+
+export const GroupListForEntity = () => {
+ return (
+
+ );
+};
diff --git a/plugins/nomad/src/hooks/useGroupForEntity.tsx b/plugins/nomad/src/hooks/useGroupForEntity.tsx
new file mode 100644
index 0000000000..22a853cbb1
--- /dev/null
+++ b/plugins/nomad/src/hooks/useGroupForEntity.tsx
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2020 The Backstage Authors
+ *
+ * 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 { useEntity } from '@backstage/plugin-catalog-react';
+import { NOMAD_GROUP_ANNOTATION } from '../Router';
+
+/**
+ * Get the entity's group and query it from the Nomad API.
+ */
+export const useGroupForEntity = () => {
+ const { entity } = useEntity();
+ const group = entity.metadata.annotations?.[NOMAD_GROUP_ANNOTATION] ?? '';
+};
diff --git a/plugins/nomad/src/plugin.test.ts b/plugins/nomad/src/plugin.test.ts
index 0de9050c70..def0f8ab89 100644
--- a/plugins/nomad/src/plugin.test.ts
+++ b/plugins/nomad/src/plugin.test.ts
@@ -13,10 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { nomadPlugin } from './plugin';
+import {
+ nomadPlugin,
+ entityContentRouteRef,
+ EntityNomadContent,
+} from './plugin';
describe('nomad', () => {
it('should export plugin', () => {
expect(nomadPlugin).toBeDefined();
});
+
+ it('should export Nomad entity ref', () => {
+ expect(entityContentRouteRef).toBeDefined();
+ });
+
+ it('should export Nomad entity', () => {
+ expect(EntityNomadContent).toBeDefined();
+ });
});
diff --git a/plugins/nomad/src/plugin.ts b/plugins/nomad/src/plugin.ts
index c5c8f81aad..535b898723 100644
--- a/plugins/nomad/src/plugin.ts
+++ b/plugins/nomad/src/plugin.ts
@@ -14,19 +14,36 @@
* limitations under the License.
*/
import {
+ configApiRef,
+ createApiFactory,
createPlugin,
createRoutableExtension,
+ createRouteRef,
} from '@backstage/core-plugin-api';
import { rootRouteRef } from './routes';
+import { NomadHttpApi, nomadApiRef } from './api';
+
+export const entityContentRouteRef = createRouteRef({
+ id: 'nomad:entity-content',
+});
export const nomadPlugin = createPlugin({
id: 'nomad',
+ apis: [
+ createApiFactory({
+ api: nomadApiRef,
+ deps: { configApi: configApiRef },
+ factory: ({ configApi }) => NomadHttpApi.fromConfig(configApi),
+ }),
+ ],
routes: {
root: rootRouteRef,
+ entityContent: entityContentRouteRef,
},
});
+/** @public */
export const NomadPage = nomadPlugin.provide(
createRoutableExtension({
name: 'NomadPage',
@@ -35,3 +52,12 @@ export const NomadPage = nomadPlugin.provide(
mountPoint: rootRouteRef,
}),
);
+
+/** @public */
+export const EntityNomadContent = nomadPlugin.provide(
+ createRoutableExtension({
+ name: 'EntityNomadContent',
+ component: () => import('./Router').then(m => m.EmbeddedRouter),
+ mountPoint: entityContentRouteRef,
+ }),
+);
diff --git a/yarn.lock b/yarn.lock
index 9417d52474..919ab12667 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7932,10 +7932,12 @@ __metadata:
dependencies:
"@backstage/catalog-model": "workspace:^"
"@backstage/cli": "workspace:^"
+ "@backstage/config": "workspace:^"
"@backstage/core-app-api": "workspace:^"
"@backstage/core-components": "workspace:^"
"@backstage/core-plugin-api": "workspace:^"
"@backstage/dev-utils": "workspace:^"
+ "@backstage/plugin-catalog-react": "workspace:^"
"@backstage/test-utils": "workspace:^"
"@backstage/theme": "workspace:^"
"@material-ui/core": ^4.9.13
@@ -7950,6 +7952,7 @@ __metadata:
react-use: ^17.2.4
peerDependencies:
react: ^16.13.1 || ^17.0.0
+ react-router-dom: "*"
languageName: unknown
linkType: soft