Merge pull request #26971 from clanghout/master
feat: render nested metadata as yaml
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes-cluster': patch
|
||||
'@backstage/plugin-kubernetes-react': patch
|
||||
---
|
||||
|
||||
Improved rendering of Kubernetes resources' metadata.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Added `nestedValuesAsYaml` option to `StructuredMetadataTable` to render data as yaml.
|
||||
@@ -73,6 +73,7 @@
|
||||
"d3-shape": "^3.0.0",
|
||||
"d3-zoom": "^3.0.0",
|
||||
"dagre": "^0.8.5",
|
||||
"js-yaml": "^4.1.0",
|
||||
"linkify-react": "4.1.3",
|
||||
"linkifyjs": "4.1.3",
|
||||
"lodash": "^4.17.21",
|
||||
|
||||
@@ -1307,6 +1307,7 @@ export interface StructuredMetadataTableProps {
|
||||
// (undocumented)
|
||||
options?: {
|
||||
titleFormat?: (key: string) => string;
|
||||
nestedValuesAsYaml?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+16
-7
@@ -66,7 +66,7 @@ describe('<StructuredMetadataTable />', () => {
|
||||
expect(getByText(startCase(value))).toBeInTheDocument();
|
||||
});
|
||||
metadata.arrayField.forEach(value => {
|
||||
expect(getByText(value)).toBeInTheDocument();
|
||||
expect(getByText(new RegExp(value))).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -124,12 +124,19 @@ describe('<StructuredMetadataTable />', () => {
|
||||
};
|
||||
|
||||
it('should make keys human readable', async () => {
|
||||
const rendered = render(<StructuredMetadataTable metadata={metadata} />);
|
||||
const rendered = render(
|
||||
<StructuredMetadataTable
|
||||
metadata={metadata}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>,
|
||||
);
|
||||
expect(rendered.queryByText(/^Test A/)).toBeInTheDocument();
|
||||
expect(rendered.queryByText(/^Test B/)).toBeInTheDocument();
|
||||
expect(rendered.queryByText(/^Test C/)).toBeInTheDocument();
|
||||
expect(rendered.queryByText(/^Test D/)).toBeInTheDocument();
|
||||
expect(rendered.queryByText(/^Test E/)).toBeInTheDocument();
|
||||
|
||||
// nested content is displayed as yaml, so not affected by formatting
|
||||
expect(rendered.queryByText(/^testC/)).toBeInTheDocument();
|
||||
expect(rendered.queryByText(/testE: stuff/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should be possible to disable it', async () => {
|
||||
@@ -161,14 +168,16 @@ describe('<StructuredMetadataTable />', () => {
|
||||
const rendered = render(
|
||||
<StructuredMetadataTable
|
||||
metadata={metadata}
|
||||
options={{ titleFormat: spongeBobCase }}
|
||||
options={{ titleFormat: spongeBobCase, nestedValuesAsYaml: true }}
|
||||
/>,
|
||||
);
|
||||
expect(rendered.queryByText(/^tEsTa/)).toBeInTheDocument();
|
||||
expect(rendered.queryByText(/^tEsTb/)).toBeInTheDocument();
|
||||
expect(rendered.queryByText(/^tEsTc/)).toBeInTheDocument();
|
||||
expect(rendered.queryByText(/^tEsTd/)).toBeInTheDocument();
|
||||
expect(rendered.queryByText(/^tEsTe/)).toBeInTheDocument();
|
||||
|
||||
// nested content is displayed as yaml, so not affected by formatting
|
||||
expect(rendered.queryByText(/^testC/)).toBeInTheDocument();
|
||||
expect(rendered.queryByText(/^testE/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+31
-14
@@ -15,21 +15,23 @@
|
||||
*/
|
||||
|
||||
import React, { Fragment, ReactElement } from 'react';
|
||||
import {
|
||||
withStyles,
|
||||
createStyles,
|
||||
WithStyles,
|
||||
Theme,
|
||||
} from '@material-ui/core/styles';
|
||||
import startCase from 'lodash/startCase';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
import {
|
||||
MetadataTable,
|
||||
MetadataTableItem,
|
||||
MetadataList,
|
||||
MetadataListItem,
|
||||
MetadataTable,
|
||||
MetadataTableItem,
|
||||
} from './MetadataTable';
|
||||
import { CodeSnippet } from '../CodeSnippet';
|
||||
import jsyaml from 'js-yaml';
|
||||
import {
|
||||
Theme,
|
||||
createStyles,
|
||||
WithStyles,
|
||||
withStyles,
|
||||
} from '@material-ui/core/styles';
|
||||
|
||||
export type StructuredMetadataTableListClassKey = 'root';
|
||||
|
||||
@@ -41,7 +43,6 @@ const listStyle = createStyles({
|
||||
});
|
||||
|
||||
export type StructuredMetadataTableNestedListClassKey = 'root';
|
||||
|
||||
const nestedListStyle = (theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
@@ -110,9 +111,24 @@ function toValue(
|
||||
if (React.isValidElement(value)) {
|
||||
return <Fragment>{value}</Fragment>;
|
||||
}
|
||||
|
||||
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
||||
return renderMap(value, options, nested);
|
||||
if (value !== null && typeof value === 'object') {
|
||||
if (options.nestedValuesAsYaml) {
|
||||
return (
|
||||
<CodeSnippet
|
||||
language="yaml"
|
||||
text={jsyaml.dump(value)}
|
||||
customStyle={{
|
||||
background: 'transparent',
|
||||
lineHeight: '1.4',
|
||||
padding: '0',
|
||||
margin: 0,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (!Array.isArray(value)) {
|
||||
return renderMap(value, options, nested);
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
@@ -122,7 +138,6 @@ function toValue(
|
||||
if (typeof value === 'boolean') {
|
||||
return <Fragment>{value ? '✅' : '❌'}</Fragment>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Typography variant="body2" component="span">
|
||||
{value}
|
||||
@@ -167,6 +182,7 @@ export interface StructuredMetadataTableProps {
|
||||
* @returns Formatted key
|
||||
*/
|
||||
titleFormat?: (key: string) => string;
|
||||
nestedValuesAsYaml?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -174,9 +190,10 @@ type Options = Required<NonNullable<StructuredMetadataTableProps['options']>>;
|
||||
|
||||
/** @public */
|
||||
export function StructuredMetadataTable(props: StructuredMetadataTableProps) {
|
||||
const { metadata, dense = true, options = {} } = props;
|
||||
const { metadata, dense = true, options } = props;
|
||||
const metadataItems = mapToItems(metadata, {
|
||||
titleFormat: startCase,
|
||||
nestedValuesAsYaml: options?.nestedValuesAsYaml ?? false,
|
||||
...options,
|
||||
});
|
||||
return <MetadataTable dense={dense}>{metadataItems}</MetadataTable>;
|
||||
|
||||
@@ -58,6 +58,7 @@ export const ClusterOverview = () => {
|
||||
'OIDC Token Provider': value.oidcTokenProvider ?? 'N/A',
|
||||
'Dashboard Link': value.dashboardUrl ?? 'N/A',
|
||||
}}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
)}
|
||||
</InfoCard>
|
||||
|
||||
@@ -50,7 +50,10 @@ const defaultColumns: TableColumn<INode>[] = [
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h5">Node Info</Typography>
|
||||
<StructuredMetadataTable metadata={node.status?.nodeInfo ?? {}} />
|
||||
<StructuredMetadataTable
|
||||
metadata={node.status?.nodeInfo ?? {}}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h5">Addresses</Typography>
|
||||
@@ -61,6 +64,7 @@ const defaultColumns: TableColumn<INode>[] = [
|
||||
return accum;
|
||||
}, {} as any) ?? {}
|
||||
}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
@@ -72,6 +76,7 @@ const defaultColumns: TableColumn<INode>[] = [
|
||||
return accum;
|
||||
}, {} as any) ?? {}
|
||||
}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -84,7 +84,10 @@ const DefaultCustomResourceAccordion = ({
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
{Object.prototype.hasOwnProperty.call(customResource, 'status') && (
|
||||
<StructuredMetadataTable metadata={customResource.status} />
|
||||
<StructuredMetadataTable
|
||||
metadata={customResource.status}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
)}
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
|
||||
+4
-4
@@ -40,13 +40,13 @@ describe('DeploymentDrawer', () => {
|
||||
expect(getAllByText('Deployment')).toHaveLength(2);
|
||||
expect(getByText('YAML')).toBeInTheDocument();
|
||||
expect(getByText('Strategy')).toBeInTheDocument();
|
||||
expect(getByText('Rolling Update:')).toBeInTheDocument();
|
||||
expect(getByText(textContentMatcher('Max Surge: 25%'))).toBeInTheDocument();
|
||||
expect(getByText('rollingUpdate:')).toBeInTheDocument();
|
||||
expect(getByText(textContentMatcher('maxSurge: 25%'))).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('Max Unavailable: 25%')),
|
||||
getByText(textContentMatcher('maxUnavailable: 25%')),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('Type: RollingUpdate')),
|
||||
getByText(textContentMatcher('type: RollingUpdate')),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Min Ready Seconds')).toBeInTheDocument();
|
||||
expect(getByText('???')).toBeInTheDocument();
|
||||
|
||||
@@ -37,13 +37,13 @@ describe('IngressDrawer', () => {
|
||||
expect(screen.getByText('YAML')).toBeInTheDocument();
|
||||
expect(screen.getByText('Rules')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(textContentMatcher('Host: api.awesome-host.io')),
|
||||
screen.getByText(textContentMatcher('host: api.awesome-host.io')),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getAllByText(textContentMatcher('Service Port: 80')),
|
||||
screen.getAllByText(textContentMatcher('servicePort: 80')),
|
||||
).toHaveLength(2);
|
||||
expect(
|
||||
screen.getAllByText(textContentMatcher('Service Name: awesome-service')),
|
||||
screen.getAllByText(textContentMatcher('serviceName: awesome-service')),
|
||||
).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -65,6 +65,9 @@ const IngressCard = ({ ingress }: IngressCardProps) => {
|
||||
metadata={{
|
||||
...ingress.spec,
|
||||
}}
|
||||
options={{
|
||||
nestedValuesAsYaml: true,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
+1
@@ -237,6 +237,7 @@ const KubernetesStructuredMetadataTableDrawerContent = <
|
||||
{!isYaml && (
|
||||
<StructuredMetadataTable
|
||||
metadata={renderObject(replaceNullsWithUndefined(object))}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -176,6 +176,7 @@ export const ContainerCard: React.FC<ContainerCardProps> = ({
|
||||
containerSpec,
|
||||
containerStatus,
|
||||
)}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
</Grid>
|
||||
{containerMetrics && (
|
||||
|
||||
@@ -39,10 +39,10 @@ describe('ServiceDrawer', () => {
|
||||
expect(screen.getByText('Cluster IP')).toBeInTheDocument();
|
||||
expect(screen.getByText('Ports')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(textContentMatcher('Target Port: 1997')),
|
||||
screen.getByText(textContentMatcher('targetPort: 1997')),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(textContentMatcher('App: awesome-service')),
|
||||
screen.getByText(textContentMatcher('app: awesome-service')),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -77,6 +77,7 @@ const ServiceCard = ({ service }: ServiceCardProps) => {
|
||||
ports: service.spec?.ports,
|
||||
...metadata,
|
||||
}}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
+6
-6
@@ -40,20 +40,20 @@ describe('StatefulSetDrawer', () => {
|
||||
expect(getByText('StatefulSet')).toBeInTheDocument();
|
||||
expect(getByText('YAML')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('Type: RollingUpdate')),
|
||||
getByText(textContentMatcher('type: RollingUpdate')),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Rolling Update:')).toBeInTheDocument();
|
||||
expect(getByText(textContentMatcher('Max Surge: 25%'))).toBeInTheDocument();
|
||||
expect(getByText('rollingUpdate:')).toBeInTheDocument();
|
||||
expect(getByText(textContentMatcher('maxSurge: 25%'))).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('Max Unavailable: 25%')),
|
||||
getByText(textContentMatcher('maxUnavailable: 25%')),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Pod Management Policy')).toBeInTheDocument();
|
||||
expect(getByText('Parallel')).toBeInTheDocument();
|
||||
expect(getByText('Service Name')).toBeInTheDocument();
|
||||
expect(getByText('Selector')).toBeInTheDocument();
|
||||
expect(getByText('Match Labels:')).toBeInTheDocument();
|
||||
expect(getByText('matchLabels:')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('App: dice-roller')),
|
||||
getByText(textContentMatcher('app: dice-roller')),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Revision History Limit')).toBeInTheDocument();
|
||||
expect(getByText('10')).toBeInTheDocument();
|
||||
|
||||
@@ -34,7 +34,10 @@ import fixture2 from '../src/__fixtures__/2-deployments.json';
|
||||
import fixture3 from '../src/__fixtures__/1-cronjobs.json';
|
||||
import fixture4 from '../src/__fixtures__/2-cronjobs.json';
|
||||
import fixture5 from '../src/__fixtures__/1-rollouts.json';
|
||||
import fixture6 from '../src/__fixtures__/3-ingresses.json';
|
||||
import fixture7 from '../src/__fixtures__/2-statefulsets.json';
|
||||
import { TestApiProvider } from '@backstage/test-utils';
|
||||
import { StructuredMetadataTable } from '@backstage/core-components';
|
||||
|
||||
const mockEntity: Entity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
@@ -134,6 +137,12 @@ class MockKubernetesClient implements KubernetesApi {
|
||||
}
|
||||
}
|
||||
|
||||
const metadata = {
|
||||
testA: 'stuff',
|
||||
testB: { testC: 'stuff' },
|
||||
testD: [{ testE: 'stuff' }],
|
||||
};
|
||||
|
||||
createDevApp()
|
||||
.addPage({
|
||||
path: '/fixture-1',
|
||||
@@ -200,5 +209,35 @@ createDevApp()
|
||||
</TestApiProvider>
|
||||
),
|
||||
})
|
||||
.addPage({
|
||||
path: '/fixture-6',
|
||||
title: 'Fixture 6',
|
||||
element: (
|
||||
<TestApiProvider
|
||||
apis={[[kubernetesApiRef, new MockKubernetesClient(fixture6)]]}
|
||||
>
|
||||
<EntityProvider entity={mockEntity}>
|
||||
<EntityKubernetesContent />
|
||||
</EntityProvider>
|
||||
</TestApiProvider>
|
||||
),
|
||||
})
|
||||
.addPage({
|
||||
path: '/fixture-7',
|
||||
title: 'Fixture 7',
|
||||
element: (
|
||||
<TestApiProvider
|
||||
apis={[[kubernetesApiRef, new MockKubernetesClient(fixture7)]]}
|
||||
>
|
||||
<EntityProvider entity={mockEntity}>
|
||||
<StructuredMetadataTable
|
||||
metadata={metadata}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
<EntityKubernetesContent />
|
||||
</EntityProvider>
|
||||
</TestApiProvider>
|
||||
),
|
||||
})
|
||||
.registerPlugin(kubernetesPlugin)
|
||||
.render();
|
||||
|
||||
@@ -0,0 +1,372 @@
|
||||
{
|
||||
"ingresses": [
|
||||
{
|
||||
"metadata": {
|
||||
"name": "app-service-endpoint.dice-roller.backstage.io",
|
||||
"namespace": "dice-roller",
|
||||
"uid": "00000000-0000-0000-0000-000000000000",
|
||||
"resourceVersion": "4749260703",
|
||||
"generation": 1,
|
||||
"creationTimestamp": "2023-08-16T14:52:16Z",
|
||||
"labels": {
|
||||
"backstage.io/kubernetes-id": "dice-roller",
|
||||
"ingress-class": "istio-internal"
|
||||
},
|
||||
"annotations": {
|
||||
"kubectl.kubernetes.io/last-applied-configuration": "spec",
|
||||
"metacontroller.k8s.io/last-applied-configuration": "spec",
|
||||
"nginx.ingress.kubernetes.io/auth-signin": "https://backstage.io/authenticate",
|
||||
"nginx.ingress.kubernetes.io/configuration-snippet": "config",
|
||||
"nginx.ingress.kubernetes.io/service-upstream": "true",
|
||||
"nginx.ingress.kubernetes.io/upstream-vhost": "app-service-endpoint.dice-roller.backstage.services"
|
||||
},
|
||||
"ownerReferences": [
|
||||
{
|
||||
"apiVersion": "networking.backstage.com/v1beta1",
|
||||
"kind": "MeshIntegration",
|
||||
"name": "app-service-endpoint",
|
||||
"uid": "00000000-0000-0000-0000-000000000000",
|
||||
"controller": true,
|
||||
"blockOwnerDeletion": true
|
||||
}
|
||||
],
|
||||
"managedFields": [
|
||||
{
|
||||
"manager": "nginx-ingress-controller",
|
||||
"operation": "Update",
|
||||
"apiVersion": "networking.k8s.io/v1",
|
||||
"time": "2023-08-16T14:52:56Z",
|
||||
"fieldsType": "FieldsV1",
|
||||
"fieldsV1": {
|
||||
"f:status": {
|
||||
"f:loadBalancer": {
|
||||
"f:ingress": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"subresource": "status"
|
||||
},
|
||||
{
|
||||
"manager": "kubectl-client-side-apply",
|
||||
"operation": "Update",
|
||||
"apiVersion": "networking.k8s.io/v1",
|
||||
"time": "2023-12-15T16:33:17Z",
|
||||
"fieldsType": "FieldsV1",
|
||||
"fieldsV1": {
|
||||
"f:metadata": {
|
||||
"f:annotations": {
|
||||
".": {},
|
||||
"f:kubectl.kubernetes.io/last-applied-configuration": {},
|
||||
"f:nginx.ingress.kubernetes.io/auth-signin": {},
|
||||
"f:nginx.ingress.kubernetes.io/configuration-snippet": {},
|
||||
"f:nginx.ingress.kubernetes.io/service-upstream": {},
|
||||
"f:nginx.ingress.kubernetes.io/upstream-vhost": {}
|
||||
},
|
||||
"f:labels": {
|
||||
".": {},
|
||||
"f:backstage.io/kubernetes-id": {},
|
||||
"f:ingress-class": {}
|
||||
}
|
||||
},
|
||||
"f:spec": {
|
||||
"f:ingressClassName": {},
|
||||
"f:rules": {},
|
||||
"f:tls": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"manager": "kubectl-label",
|
||||
"operation": "Update",
|
||||
"apiVersion": "networking.k8s.io/v1",
|
||||
"time": "2024-02-21T15:00:44Z",
|
||||
"fieldsType": "FieldsV1",
|
||||
"fieldsV1": {
|
||||
"f:metadata": {
|
||||
"f:labels": {
|
||||
"f:controller-uid": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"manager": "metacontroller",
|
||||
"operation": "Update",
|
||||
"apiVersion": "networking.k8s.io/v1",
|
||||
"time": "2024-02-21T15:01:01Z",
|
||||
"fieldsType": "FieldsV1",
|
||||
"fieldsV1": {
|
||||
"f:metadata": {
|
||||
"f:annotations": {
|
||||
"f:metacontroller.k8s.io/last-applied-configuration": {}
|
||||
},
|
||||
"f:ownerReferences": {
|
||||
".": {},
|
||||
"k:{\"uid\":\"00000000-0000-0000-0000-000000000000\"}": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"spec": {
|
||||
"ingressClassName": "istio-internal",
|
||||
"tls": {
|
||||
"hosts": ["app-service-endpoint.dice-roller.backstage.io"],
|
||||
"secretName": "dice-roller-wildcard-certificate"
|
||||
},
|
||||
"rules": [
|
||||
{
|
||||
"host": "app-service-endpoint.dice-roller.backstage.io",
|
||||
"http": {
|
||||
"paths": [
|
||||
{
|
||||
"pathType": "ImplementationSpecific",
|
||||
"backend": {
|
||||
"service": {
|
||||
"name": "app-service-endpoint",
|
||||
"port": {
|
||||
"number": 8080
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"pathType": "Second item in the list",
|
||||
"backend": {
|
||||
"service": {
|
||||
"name": "app-service-endpoint",
|
||||
"port": {
|
||||
"number": 8080
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {
|
||||
"ingress": [
|
||||
{
|
||||
"ip": "1.2.3.4"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"deployments": [
|
||||
{
|
||||
"metadata": {
|
||||
"annotations": {
|
||||
"deployment.kubernetes.io/revision": "2",
|
||||
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"annotations\":{},\"labels\":{\"backstage.io/kubernetes-id\":\"dice-roller\"},\"name\":\"dice-roller\",\"namespace\":\"default\"},\"spec\":{\"replicas\":10,\"selector\":{\"matchLabels\":{\"app\":\"dice-roller\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"dice-roller\",\"backstage.io/kubernetes-id\":\"dice-roller\"}},\"spec\":{\"containers\":[{\"image\":\"nginx:1.14.2\",\"name\":\"nginx\",\"ports\":[{\"containerPort\":80}]}]}}}}\n"
|
||||
},
|
||||
"creationTimestamp": "2020-09-23T12:00:55.000Z",
|
||||
"generation": 3,
|
||||
"labels": {
|
||||
"backstage.io/kubernetes-id": "dice-roller"
|
||||
},
|
||||
"managedFields": [
|
||||
{
|
||||
"apiVersion": "apps/v1",
|
||||
"fieldsType": "FieldsV1",
|
||||
"fieldsV1": {
|
||||
"f:metadata": {
|
||||
"f:annotations": {
|
||||
".": {},
|
||||
"f:kubectl.kubernetes.io/last-applied-configuration": {}
|
||||
},
|
||||
"f:labels": {
|
||||
".": {},
|
||||
"f:backstage.io/kubernetes-id": {}
|
||||
}
|
||||
},
|
||||
"f:spec": {
|
||||
"f:progressDeadlineSeconds": {},
|
||||
"f:replicas": {},
|
||||
"f:revisionHistoryLimit": {},
|
||||
"f:selector": {
|
||||
"f:matchLabels": {
|
||||
".": {},
|
||||
"f:app": {}
|
||||
}
|
||||
},
|
||||
"f:strategy": {
|
||||
"f:rollingUpdate": {
|
||||
".": {},
|
||||
"f:maxSurge": {},
|
||||
"f:maxUnavailable": {}
|
||||
},
|
||||
"f:type": {}
|
||||
},
|
||||
"f:template": {
|
||||
"f:metadata": {
|
||||
"f:labels": {
|
||||
".": {},
|
||||
"f:app": {},
|
||||
"f:backstage.io/kubernetes-id": {}
|
||||
}
|
||||
},
|
||||
"f:spec": {
|
||||
"f:containers": {
|
||||
"k:{\"name\":\"nginx\"}": {
|
||||
".": {},
|
||||
"f:image": {},
|
||||
"f:imagePullPolicy": {},
|
||||
"f:name": {},
|
||||
"f:ports": {
|
||||
".": {},
|
||||
"k:{\"containerPort\":80,\"protocol\":\"TCP\"}": {
|
||||
".": {},
|
||||
"f:containerPort": {},
|
||||
"f:protocol": {}
|
||||
}
|
||||
},
|
||||
"f:resources": {},
|
||||
"f:terminationMessagePath": {},
|
||||
"f:terminationMessagePolicy": {}
|
||||
}
|
||||
},
|
||||
"f:dnsPolicy": {},
|
||||
"f:restartPolicy": {},
|
||||
"f:schedulerName": {},
|
||||
"f:securityContext": {},
|
||||
"f:terminationGracePeriodSeconds": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"manager": "kubectl",
|
||||
"operation": "Update",
|
||||
"time": "2020-09-25T09:58:50.000Z"
|
||||
},
|
||||
{
|
||||
"apiVersion": "apps/v1",
|
||||
"fieldsType": "FieldsV1",
|
||||
"fieldsV1": {
|
||||
"f:metadata": {
|
||||
"f:annotations": {
|
||||
"f:deployment.kubernetes.io/revision": {}
|
||||
}
|
||||
},
|
||||
"f:status": {
|
||||
"f:availableReplicas": {},
|
||||
"f:conditions": {
|
||||
".": {},
|
||||
"k:{\"type\":\"Available\"}": {
|
||||
".": {},
|
||||
"f:lastTransitionTime": {},
|
||||
"f:lastUpdateTime": {},
|
||||
"f:message": {},
|
||||
"f:reason": {},
|
||||
"f:status": {},
|
||||
"f:type": {}
|
||||
},
|
||||
"k:{\"type\":\"Progressing\"}": {
|
||||
".": {},
|
||||
"f:lastTransitionTime": {},
|
||||
"f:lastUpdateTime": {},
|
||||
"f:message": {},
|
||||
"f:reason": {},
|
||||
"f:status": {},
|
||||
"f:type": {}
|
||||
}
|
||||
},
|
||||
"f:observedGeneration": {},
|
||||
"f:readyReplicas": {},
|
||||
"f:replicas": {},
|
||||
"f:updatedReplicas": {}
|
||||
}
|
||||
},
|
||||
"manager": "kube-controller-manager",
|
||||
"operation": "Update",
|
||||
"time": "2020-09-25T09:58:55.000Z"
|
||||
}
|
||||
],
|
||||
"name": "dice-roller",
|
||||
"namespace": "default",
|
||||
"resourceVersion": "593230",
|
||||
"selfLink": "/apis/apps/v1/namespaces/default/deployments/dice-roller",
|
||||
"uid": "7551e949-42d1-4061-83c5-9da107186e47"
|
||||
},
|
||||
"spec": {
|
||||
"progressDeadlineSeconds": 600,
|
||||
"replicas": 10,
|
||||
"revisionHistoryLimit": 10,
|
||||
"selector": {
|
||||
"matchLabels": {
|
||||
"app": "dice-roller"
|
||||
}
|
||||
},
|
||||
"strategy": {
|
||||
"rollingUpdate": {
|
||||
"maxSurge": "25%",
|
||||
"maxUnavailable": "25%"
|
||||
},
|
||||
"type": "RollingUpdate"
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app": "dice-roller",
|
||||
"backstage.io/kubernetes-id": "dice-roller"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"image": "nginx:1.14.2",
|
||||
"imagePullPolicy": "IfNotPresent",
|
||||
"name": "nginx",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 80,
|
||||
"protocol": "TCP"
|
||||
}
|
||||
],
|
||||
"resources": {},
|
||||
"terminationMessagePath": "/dev/termination-log",
|
||||
"terminationMessagePolicy": "File"
|
||||
}
|
||||
],
|
||||
"dnsPolicy": "ClusterFirst",
|
||||
"restartPolicy": "Always",
|
||||
"schedulerName": "default-scheduler",
|
||||
"securityContext": {},
|
||||
"terminationGracePeriodSeconds": 30
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"availableReplicas": 10,
|
||||
"conditions": [
|
||||
{
|
||||
"lastTransitionTime": "2020-09-23T12:00:55.000Z",
|
||||
"lastUpdateTime": "2020-09-24T11:39:28.000Z",
|
||||
"message": "ReplicaSet \"dice-roller-6c8646bfd\" has successfully progressed.",
|
||||
"reason": "NewReplicaSetAvailable",
|
||||
"status": "True",
|
||||
"type": "Progressing"
|
||||
},
|
||||
{
|
||||
"lastTransitionTime": "2020-09-25T09:58:55.000Z",
|
||||
"lastUpdateTime": "2020-09-25T09:58:55.000Z",
|
||||
"message": "Deployment has minimum availability.",
|
||||
"reason": "MinimumReplicasAvailable",
|
||||
"status": "True",
|
||||
"type": "Available"
|
||||
}
|
||||
],
|
||||
"observedGeneration": 3,
|
||||
"readyReplicas": 10,
|
||||
"replicas": 10,
|
||||
"updatedReplicas": 10
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user