-
Notifications
You must be signed in to change notification settings - Fork 705
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Show URL for ingress objects * Rename helper files * Print Ingress first * Update test example
- Loading branch information
1 parent
c6bccdf
commit 475b0ff
Showing
14 changed files
with
636 additions
and
257 deletions.
There are no files selected for viewing
76 changes: 76 additions & 0 deletions
76
dashboard/src/components/AppView/AccessURLTable/AccessURLItem/AccessURLIngressHelper.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { IHTTPIngressPath, IIngressRule, IIngressSpec, IResource } from "shared/types"; | ||
import { GetURLItemFromIngress } from "./AccessURLIngressHelper"; | ||
|
||
describe("GetURLItemFromIngress", () => { | ||
interface Itest { | ||
description: string; | ||
hosts: string[]; | ||
paths: IHTTPIngressPath[]; | ||
tlsHosts: string[]; | ||
expectedURLs: string[]; | ||
} | ||
const tests: Itest[] = [ | ||
{ | ||
description: "it should show the host without port", | ||
hosts: ["foo.bar"], | ||
paths: [], | ||
tlsHosts: [], | ||
expectedURLs: ["http://foo.bar"], | ||
}, | ||
{ | ||
description: "it should show several hosts without port", | ||
hosts: ["foo.bar", "not-foo.bar"], | ||
paths: [], | ||
tlsHosts: [], | ||
expectedURLs: ["http://foo.bar", "http://not-foo.bar"], | ||
}, | ||
{ | ||
description: "it should show the host with the different paths", | ||
hosts: ["foo.bar"], | ||
paths: [{ path: "/one" }, { path: "/two" }], | ||
tlsHosts: [], | ||
expectedURLs: ["http://foo.bar/one", "http://foo.bar/two"], | ||
}, | ||
{ | ||
description: "it should show TLS hosts with https", | ||
hosts: ["foo.bar", "not-foo.bar"], | ||
paths: [], | ||
tlsHosts: ["foo.bar"], | ||
expectedURLs: ["https://foo.bar", "http://not-foo.bar"], | ||
}, | ||
]; | ||
tests.forEach(test => { | ||
it(test.description, () => { | ||
const ingress = { | ||
metadata: { | ||
name: "foo", | ||
}, | ||
spec: { | ||
rules: [], | ||
} as IIngressSpec, | ||
} as IResource; | ||
test.hosts.forEach(h => { | ||
const rule = { | ||
host: h, | ||
http: { | ||
paths: [], | ||
}, | ||
} as IIngressRule; | ||
if (test.paths.length > 0) { | ||
rule.http.paths = test.paths; | ||
} | ||
ingress.spec.rules.push(rule); | ||
}); | ||
if (test.tlsHosts.length > 0) { | ||
ingress.spec.tls = [ | ||
{ | ||
hosts: test.tlsHosts, | ||
}, | ||
]; | ||
} | ||
const ingressItem = GetURLItemFromIngress(ingress); | ||
expect(ingressItem.isLink).toBe(true); | ||
expect(ingressItem.URLs).toEqual(test.expectedURLs); | ||
}); | ||
}); | ||
}); |
40 changes: 40 additions & 0 deletions
40
dashboard/src/components/AppView/AccessURLTable/AccessURLItem/AccessURLIngressHelper.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { IIngressSpec, IIngressTLS, IResource } from "shared/types"; | ||
import { IURLItem } from "./IURLItem"; | ||
|
||
// URLs returns the list of URLs obtained from the service status | ||
function URLs(ingress: IResource): string[] { | ||
const spec = ingress.spec as IIngressSpec; | ||
const res: string[] = []; | ||
spec.rules.forEach(r => { | ||
if (r.http.paths.length > 0) { | ||
r.http.paths.forEach(p => { | ||
res.push(getURL(r.host, spec.tls, p.path)); | ||
}); | ||
} else { | ||
res.push(getURL(r.host, spec.tls)); | ||
} | ||
}); | ||
return res; | ||
} | ||
|
||
// getURL returns a full URL based on a hostname, a TLS configuration and a optional path | ||
function getURL(hostname: string, tls?: IIngressTLS[], path?: string) { | ||
// If the hostname is configured within the TLS hosts it will use HTTPS | ||
const protocol = | ||
tls && | ||
tls.some(tlsRule => { | ||
return tlsRule.hosts.indexOf(hostname) > -1; | ||
}) | ||
? "https" | ||
: "http"; | ||
return `${protocol}://${hostname}${path || ""}`; | ||
} | ||
|
||
export function GetURLItemFromIngress(ingress: IResource) { | ||
return { | ||
name: ingress.metadata.name, | ||
type: "Ingress", | ||
isLink: true, | ||
URLs: URLs(ingress), | ||
} as IURLItem; | ||
} |
123 changes: 20 additions & 103 deletions
123
dashboard/src/components/AppView/AccessURLTable/AccessURLItem/AccessURLItem.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,111 +1,28 @@ | ||
import { shallow } from "enzyme"; | ||
import context from "jest-plugin-context"; | ||
import * as React from "react"; | ||
|
||
import { IResource, IServiceSpec, IServiceStatus } from "shared/types"; | ||
import AccessURLItem from "./AccessURLItem"; | ||
import { IURLItem } from "./IURLItem"; | ||
|
||
context("when the status is empty", () => { | ||
const service = { | ||
metadata: { | ||
name: "foo", | ||
}, | ||
spec: { | ||
type: "LoadBalancer", | ||
ports: [{ port: 8080 }], | ||
} as IServiceSpec, | ||
status: { | ||
loadBalancer: {}, | ||
} as IServiceStatus, | ||
} as IResource; | ||
|
||
it("should show a Pending text", () => { | ||
const wrapper = shallow(<AccessURLItem loadBalancerService={service} />); | ||
expect(wrapper.text()).toContain("Pending"); | ||
expect(wrapper).toMatchSnapshot(); | ||
}); | ||
|
||
it("should not include a link", () => { | ||
const wrapper = shallow(<AccessURLItem loadBalancerService={service} />); | ||
expect(wrapper.find(".ServiceItem")).toExist(); | ||
const link = wrapper.find(".ServiceItem").find("a"); | ||
expect(link).not.toExist(); | ||
}); | ||
it("should show only a message (without a link) if the item is not a link", () => { | ||
const item = { name: "foo", isLink: false, URLs: ["Pending"] } as IURLItem; | ||
const wrapper = shallow(<AccessURLItem URLItem={item} />); | ||
expect(wrapper.text()).toContain("Pending"); | ||
expect(wrapper).toMatchSnapshot(); | ||
const link = wrapper.find(".ServiceItem").find("a"); | ||
expect(link).not.toExist(); | ||
}); | ||
|
||
context("when the status is populated", () => { | ||
interface Itest { | ||
description: string; | ||
ports: any[]; | ||
ingress: any[]; | ||
expectedURLs: string[]; | ||
} | ||
const tests: Itest[] = [ | ||
{ | ||
description: "it should show the IP and port if it's not known", | ||
ports: [{ port: 8080 }], | ||
ingress: [{ ip: "1.2.3.4" }], | ||
expectedURLs: ["http://1.2.3.4:8080"], | ||
}, | ||
{ | ||
description: "it should show the hostname and port if it's not known", | ||
ports: [{ port: 8080 }], | ||
ingress: [{ hostname: "1.2.3.4" }], | ||
expectedURLs: ["http://1.2.3.4:8080"], | ||
}, | ||
{ | ||
description: "it should show the IP and skip the port if it's known", | ||
ports: [{ port: 80 }], | ||
ingress: [{ ip: "1.2.3.4" }], | ||
expectedURLs: ["http://1.2.3.4"], | ||
}, | ||
{ | ||
description: "it should show the https URL if the port is 443", | ||
ports: [{ port: 443 }], | ||
ingress: [{ ip: "1.2.3.4" }], | ||
expectedURLs: ["https://1.2.3.4"], | ||
}, | ||
{ | ||
description: "it should show several URLs if there are multipe ports", | ||
ports: [{ port: 8080 }, { port: 8081 }], | ||
ingress: [{ ip: "1.2.3.4" }], | ||
expectedURLs: ["http://1.2.3.4:8080", "http://1.2.3.4:8081"], | ||
}, | ||
{ | ||
description: "it should show several URLs if there are ingress ports", | ||
ports: [{ port: 8080 }, { port: 8081 }], | ||
ingress: [{ ip: "1.2.3.4" }, { hostname: "foo.bar" }], | ||
expectedURLs: [ | ||
"http://1.2.3.4:8080", | ||
"http://1.2.3.4:8081", | ||
"http://foo.bar:8080", | ||
"http://foo.bar:8081", | ||
], | ||
}, | ||
]; | ||
tests.forEach(test => { | ||
it(test.description, () => { | ||
const service = { | ||
metadata: { | ||
name: "foo", | ||
}, | ||
spec: { | ||
type: "LoadBalancer", | ||
ports: test.ports, | ||
}, | ||
status: { | ||
loadBalancer: { | ||
ingress: test.ingress, | ||
}, | ||
} as IServiceStatus, | ||
} as IResource; | ||
const wrapper = shallow(<AccessURLItem loadBalancerService={service} />); | ||
test.expectedURLs.forEach(url => { | ||
expect(wrapper.find(".ServiceItem")).toExist(); | ||
const link = wrapper.find(".ServiceItem").find("a"); | ||
expect(link).toExist(); | ||
expect(wrapper.text()).toContain(url); | ||
}); | ||
}); | ||
}); | ||
it("should show only an URL with a link", () => { | ||
const item = { | ||
name: "foo", | ||
isLink: true, | ||
URLs: ["http://1.2.3.4:8080", "https://foo.bar"], | ||
} as IURLItem; | ||
const wrapper = shallow(<AccessURLItem URLItem={item} />); | ||
expect(wrapper.text()).toContain("http://1.2.3.4:8080"); | ||
expect(wrapper.text()).toContain("https://foo.bar"); | ||
expect(wrapper).toMatchSnapshot(); | ||
const link = wrapper.find(".ServiceItem").find("a"); | ||
expect(link).toExist(); | ||
}); |
102 changes: 29 additions & 73 deletions
102
dashboard/src/components/AppView/AccessURLTable/AccessURLItem/AccessURLItem.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,38 @@ | ||
import * as React from "react"; | ||
|
||
import { IResource, IServiceSpec, IServiceStatus } from "../../../../shared/types"; | ||
import "./AccessURLItem.css"; | ||
import { IURLItem } from "./IURLItem"; | ||
|
||
interface IAccessURLItem { | ||
loadBalancerService: IResource; | ||
URLItem: IURLItem; | ||
} | ||
|
||
class AccessURLItem extends React.Component<IAccessURLItem> { | ||
public render() { | ||
const { loadBalancerService } = this.props; | ||
const isLink = this.isLink(); | ||
return ( | ||
<tr> | ||
<td>{loadBalancerService.metadata.name}</td> | ||
<td>{loadBalancerService.spec.type}</td> | ||
<td> | ||
{this.URLs().map(l => ( | ||
<span | ||
key={l} | ||
className={`ServiceItem ${ | ||
isLink ? "ServiceItem--with-link" : "" | ||
} type-small margin-r-small padding-tiny padding-h-normal`} | ||
> | ||
{isLink ? ( | ||
<a className="padding-tiny padding-h-normal" href={l} target="_blank"> | ||
{l} | ||
</a> | ||
) : ( | ||
l | ||
)} | ||
</span> | ||
))} | ||
</td> | ||
</tr> | ||
); | ||
} | ||
|
||
// isLink returns true if there are any link in the Item | ||
private isLink(): boolean { | ||
if ( | ||
this.props.loadBalancerService.status.loadBalancer.ingress && | ||
this.props.loadBalancerService.status.loadBalancer.ingress.length | ||
) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
// URLs returns the list of URLs obtained from the service status | ||
private URLs(): string[] { | ||
const URLs: string[] = []; | ||
const { loadBalancerService } = this.props; | ||
const status: IServiceStatus = loadBalancerService.status; | ||
if (status.loadBalancer.ingress && status.loadBalancer.ingress.length) { | ||
status.loadBalancer.ingress.forEach(i => { | ||
(loadBalancerService.spec as IServiceSpec).ports.forEach(port => { | ||
if (i.hostname) { | ||
URLs.push(this.getURL(i.hostname, port.port)); | ||
} | ||
if (i.ip) { | ||
URLs.push(this.getURL(i.ip, port.port)); | ||
} | ||
}); | ||
}); | ||
} else { | ||
URLs.push("Pending"); | ||
} | ||
return URLs; | ||
} | ||
|
||
// getURL returns a full URL adding the protocol and the port if needed | ||
private getURL(base: string, port: number) { | ||
const protocol = port === 443 ? "https" : "http"; | ||
// Only show the port in the URL if it's not a standard HTTP/HTTPS port | ||
const portSuffix = port === 443 || port === 80 ? "" : `:${port}`; | ||
return `${protocol}://${base}${portSuffix}`; | ||
} | ||
} | ||
const AccessURLItem: React.SFC<IAccessURLItem> = props => { | ||
const { URLItem } = props; | ||
return ( | ||
<tr> | ||
<td>{URLItem.name}</td> | ||
<td>{URLItem.type}</td> | ||
<td> | ||
{URLItem.URLs.map(l => ( | ||
<span | ||
key={l} | ||
className={`ServiceItem ${ | ||
URLItem.isLink ? "ServiceItem--with-link" : "" | ||
} type-small margin-r-small padding-tiny padding-h-normal`} | ||
> | ||
{URLItem.isLink ? ( | ||
<a className="padding-tiny padding-h-normal" href={l} target="_blank"> | ||
{l} | ||
</a> | ||
) : ( | ||
l | ||
)} | ||
</span> | ||
))} | ||
</td> | ||
</tr> | ||
); | ||
}; | ||
|
||
export default AccessURLItem; |
Oops, something went wrong.