parent
069e56f921
commit
54d4b61250
@ -782,6 +782,7 @@ exports[`renders <Hostname values /> without throwing 1`] = `
|
||||
Instance name
|
||||
|
||||
hostname
|
||||
s
|
||||
</small>
|
||||
<div
|
||||
className="c4"
|
||||
|
@ -75,7 +75,7 @@ export const Hostname = ({ values, network, service, ...hostname }) => (
|
||||
: network
|
||||
? 'Network'
|
||||
: service ? 'CNS service' : 'Instance name'}{' '}
|
||||
hostname
|
||||
hostname{values.length === 1 ? '' : 's'}
|
||||
</SmallBordered>
|
||||
<FlexItem>
|
||||
<Margin right={1}>
|
||||
|
161
packages/my-joy-beta/src/components/create-instance/firewall.js
Normal file
161
packages/my-joy-beta/src/components/create-instance/firewall.js
Normal file
@ -0,0 +1,161 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { Field } from 'redux-form';
|
||||
import { Margin, Padding } from 'styled-components-spacing';
|
||||
import Flex, { FlexItem } from 'styled-flex-component';
|
||||
import styled from 'styled-components';
|
||||
import remcalc from 'remcalc';
|
||||
import constantCase from 'constant-case';
|
||||
|
||||
import {
|
||||
NameIcon,
|
||||
H3,
|
||||
P,
|
||||
FormGroup,
|
||||
FormLabel,
|
||||
Input,
|
||||
FormMeta,
|
||||
Button,
|
||||
Toggle,
|
||||
Card,
|
||||
CardOutlet,
|
||||
Divider,
|
||||
Row,
|
||||
Col,
|
||||
TagList
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
import Tag from '@components/instances/tags';
|
||||
import Title from './title';
|
||||
|
||||
const Box = styled.div`
|
||||
display: inline-block;
|
||||
background-color: ${props => props.theme.white};
|
||||
border: ${remcalc(1)} solid ${props => props.theme.grey};
|
||||
min-width: 100%;
|
||||
`;
|
||||
|
||||
const Wildcards = {
|
||||
vmall: 'All VMs in DC',
|
||||
any: 'Any'
|
||||
};
|
||||
|
||||
const parsePartial = (p, index) => {
|
||||
if (p[0] === 'wildcard') {
|
||||
return <span key={index}>{Wildcards[p[1]]}</span>;
|
||||
}
|
||||
|
||||
if (p[0] === 'tag') {
|
||||
const value = Array.isArray(p[1]) ? p[1][1] : '';
|
||||
const name = Array.isArray(p[1]) ? p[1][0] : p[1];
|
||||
|
||||
return <Tag key={index} name={name} value={value} />;
|
||||
}
|
||||
}
|
||||
|
||||
const Rule = ({ enabled, rule_obj }) => {
|
||||
const { action, protocol } = rule_obj;
|
||||
|
||||
const froms = rule_obj.from.map(parsePartial);
|
||||
const tos = rule_obj.to.map(parsePartial);
|
||||
|
||||
return (
|
||||
<Box disabled={!enabled}>
|
||||
<Padding left={3} right={3} top={2} bottom={2}>
|
||||
<Row>
|
||||
<Col xs={3}>
|
||||
<Flex justifyStart alignCenter contentStretch>
|
||||
<FlexItem>
|
||||
<b>From:{' '}</b>
|
||||
</FlexItem>
|
||||
<FlexItem grow={1}><TagList>{froms}</TagList></FlexItem>
|
||||
</Flex>
|
||||
</Col>
|
||||
<Col xs={3}>
|
||||
<Flex justifyStart alignCenter contentStretch>
|
||||
<FlexItem>
|
||||
<b>To:{' '}</b>
|
||||
</FlexItem>
|
||||
<FlexItem grow={1}><TagList>{tos}</TagList></FlexItem>
|
||||
</Flex>
|
||||
</Col>
|
||||
<Col xs={2}>
|
||||
<Flex justifyStart alignCenter contentStretch>
|
||||
<FlexItem>
|
||||
<b>Protocol:{' '}</b>
|
||||
</FlexItem>
|
||||
<FlexItem grow={1}>{protocol.name}</FlexItem>
|
||||
</Flex>
|
||||
</Col>
|
||||
<Col xs={2}>
|
||||
<Flex justifyStart alignCenter contentStretch>
|
||||
<FlexItem>
|
||||
<b>Ports:{' '}</b>
|
||||
</FlexItem>
|
||||
<FlexItem grow={1}>{protocol.targets.join(';')}</FlexItem>
|
||||
</Flex>
|
||||
</Col>
|
||||
<Col xs={2}>
|
||||
<Flex justifyStart alignCenter contentStretch>
|
||||
<FlexItem>
|
||||
<b>Action:{' '}</b>
|
||||
</FlexItem>
|
||||
<FlexItem grow={1}>{constantCase(action)}</FlexItem>
|
||||
</Flex>
|
||||
</Col>
|
||||
</Row>
|
||||
</Padding>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default ({
|
||||
defaultRules = [],
|
||||
tagRules = [],
|
||||
enabled = false,
|
||||
handleSubmit
|
||||
}) => (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Margin bottom={4}>
|
||||
<FormGroup name="enabled" field={Field}>
|
||||
<Toggle>Enable firewall rules</Toggle>
|
||||
</FormGroup>
|
||||
{enabled ? (
|
||||
<FormGroup name="show-inactive" field={Field}>
|
||||
<Toggle>Show inactive rules</Toggle>
|
||||
</FormGroup>
|
||||
) : null}
|
||||
</Margin>
|
||||
{enabled && defaultRules.length ? (
|
||||
<Fragment>
|
||||
<H3>Default firewall rules</H3>
|
||||
<span /> {/* trick H3 margin sibling rule */}
|
||||
<Margin top={3}>
|
||||
{defaultRules.map(rule => (
|
||||
<Margin bottom={2}>
|
||||
<Rule key={rule.id} {...rule} />
|
||||
</Margin>
|
||||
))}
|
||||
</Margin>
|
||||
</Fragment>
|
||||
) : null}
|
||||
{enabled && tagRules.length && defaultRules.length ? (
|
||||
<Divider height={remcalc(18)} transparent />
|
||||
) : null}
|
||||
{enabled && tagRules.length ? (
|
||||
<Fragment>
|
||||
<H3>Firewall rules from instance tags</H3>
|
||||
<span /> {/* trick H3 margin sibling rule */}
|
||||
<Margin top={3}>
|
||||
{tagRules.map(rule => (
|
||||
<Margin bottom={2}>
|
||||
<Rule key={rule.id} {...rule} />
|
||||
</Margin>
|
||||
))}
|
||||
</Margin>
|
||||
</Fragment>
|
||||
) : null}
|
||||
{enabled && (tagRules.length || defaultRules.length) ? (
|
||||
<Divider height={remcalc(12)} transparent />
|
||||
) : null}
|
||||
</form>
|
||||
);
|
@ -163,7 +163,6 @@ Array [
|
||||
/>
|
||||
</div>,
|
||||
<form />,
|
||||
<div />,
|
||||
]
|
||||
`;
|
||||
|
||||
@ -329,7 +328,6 @@ Array [
|
||||
height="0.0625rem"
|
||||
/>
|
||||
</div>,
|
||||
<div />,
|
||||
]
|
||||
`;
|
||||
|
||||
@ -754,16 +752,14 @@ Array [
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
<div>
|
||||
<button
|
||||
className="c0 c1 c2"
|
||||
href=""
|
||||
onClick={undefined}
|
||||
type="button"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>,
|
||||
<button
|
||||
className="c0 c1 c2"
|
||||
href=""
|
||||
onClick={undefined}
|
||||
type="button"
|
||||
>
|
||||
Next
|
||||
</button>,
|
||||
]
|
||||
`;
|
||||
|
||||
@ -1226,7 +1222,6 @@ Array [
|
||||
</div>
|
||||
</div>
|
||||
</form>,
|
||||
<div />,
|
||||
]
|
||||
`;
|
||||
|
||||
@ -2746,16 +2741,14 @@ Array [
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
<div>
|
||||
<button
|
||||
className="c0 c1 c2"
|
||||
href=""
|
||||
onClick={undefined}
|
||||
type="button"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>,
|
||||
<button
|
||||
className="c0 c1 c2"
|
||||
href=""
|
||||
onClick={undefined}
|
||||
type="button"
|
||||
>
|
||||
Next
|
||||
</button>,
|
||||
]
|
||||
`;
|
||||
|
||||
@ -3370,15 +3363,13 @@ Array [
|
||||
border-color: rgb(216,216,216);
|
||||
}
|
||||
|
||||
<div>
|
||||
<button
|
||||
className="c0 c1 c2"
|
||||
href=""
|
||||
onClick={undefined}
|
||||
type="button"
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
</div>,
|
||||
<button
|
||||
className="c0 c1 c2"
|
||||
href=""
|
||||
onClick={undefined}
|
||||
type="button"
|
||||
>
|
||||
Edit
|
||||
</button>,
|
||||
]
|
||||
`;
|
||||
|
142
packages/my-joy-beta/src/containers/create-instance/firewall.js
Normal file
142
packages/my-joy-beta/src/containers/create-instance/firewall.js
Normal file
@ -0,0 +1,142 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { compose, graphql } from 'react-apollo';
|
||||
import { Margin } from 'styled-components-spacing';
|
||||
import ReduxForm from 'declarative-redux-form';
|
||||
import { set } from 'react-redux-values';
|
||||
import { connect } from 'react-redux';
|
||||
import get from 'lodash.get';
|
||||
import find from 'lodash.find';
|
||||
import forceArray from 'force-array';
|
||||
|
||||
import Title from '@components/create-instance/title';
|
||||
import FirewallForm from '@components/create-instance/firewall';
|
||||
import ListFwRules from '@graphql/list-fw-rules.gql';
|
||||
|
||||
import { StatusLoader, FirewallIcon, P, H3, Button } from 'joyent-ui-toolkit';
|
||||
|
||||
const FORM_NAME = 'CREATE-INSTANCE-FIREWALL';
|
||||
|
||||
const Firewall = ({
|
||||
defaultRules = [],
|
||||
tagRules = [],
|
||||
expanded = false,
|
||||
proceeded = false,
|
||||
loading = false,
|
||||
enabled = false,
|
||||
handleNext,
|
||||
handleEdit
|
||||
}) => (
|
||||
<Fragment>
|
||||
<Title icon={<FirewallIcon />}>Firewall</Title>
|
||||
{expanded ? (
|
||||
<Margin bottom={3}>
|
||||
<P>
|
||||
Cloud Firewall rules control traffic across instances. Enabling the
|
||||
firewall adds a default set of rules and rules defined by your chosen
|
||||
tags.{' '}
|
||||
<a
|
||||
target="__blank"
|
||||
href="https://docs.joyent.com/public-cloud/network/firewall"
|
||||
>
|
||||
Read more
|
||||
</a>
|
||||
</P>
|
||||
</Margin>
|
||||
) : null}
|
||||
{loading && expanded ? <StatusLoader /> : null}
|
||||
{!loading ? (
|
||||
<ReduxForm
|
||||
form={FORM_NAME}
|
||||
destroyOnUnmount={false}
|
||||
forceUnregisterOnUnmount={true}
|
||||
>
|
||||
{props =>
|
||||
expanded ? (
|
||||
<FirewallForm
|
||||
{...props}
|
||||
defaultRules={defaultRules}
|
||||
tagRules={tagRules}
|
||||
enabled={enabled}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
</ReduxForm>
|
||||
) : null}
|
||||
{proceeded && !expanded ? (
|
||||
<Margin bottom={4}>
|
||||
<H3>{enabled ? 'Firewall Enabled' : 'Firewall Not Enabled'}</H3>
|
||||
</Margin>
|
||||
) : null}
|
||||
<Fragment>
|
||||
{expanded ? (
|
||||
<Button type="button" onClick={handleNext}>
|
||||
Next
|
||||
</Button>
|
||||
) : proceeded ? (
|
||||
<Button type="button" onClick={handleEdit} secondary>
|
||||
Edit
|
||||
</Button>
|
||||
) : null}
|
||||
</Fragment>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
export default compose(
|
||||
connect(
|
||||
({ form, values }, ownProps) => ({
|
||||
...ownProps,
|
||||
enabled: get(form, `${FORM_NAME}.values.enabled`, false),
|
||||
showInactive: get(form, `${FORM_NAME}.values.show-inactive`, false),
|
||||
tags: get(values, 'create-instance-tags', [])
|
||||
}),
|
||||
(dispatch, { history }) => ({
|
||||
handleNext: () => {
|
||||
dispatch(
|
||||
set({ name: 'create-instance-firewall-proceeded', value: true })
|
||||
);
|
||||
|
||||
return history.push('/instances/~create/cns');
|
||||
},
|
||||
handleEdit: () => {
|
||||
return history.push('/instances/~create/firewall');
|
||||
}
|
||||
})
|
||||
),
|
||||
graphql(ListFwRules, {
|
||||
options: ({ tags, expanded, enabled }) => ({
|
||||
fetchPolicy: expanded && enabled ? 'cache-first' : 'cache-only',
|
||||
variables: {
|
||||
tags: tags.map(({ name, value }) => ({ name, value }))
|
||||
}
|
||||
}),
|
||||
props: ({ ownProps, data }) => {
|
||||
const { enabled, showInactive, tags = [] } = ownProps;
|
||||
|
||||
const {
|
||||
firewall_rules_create_machine = [],
|
||||
loading,
|
||||
error,
|
||||
refetch
|
||||
} = data;
|
||||
|
||||
const rules = forceArray(firewall_rules_create_machine)
|
||||
.filter(({ enabled }) => enabled || showInactive)
|
||||
.map(({ rule_obj, ...rule }) => ({
|
||||
...rule,
|
||||
rule_obj: {
|
||||
...rule_obj,
|
||||
from: forceArray(rule_obj.from).map(f => forceArray(f)),
|
||||
to: forceArray(rule_obj.to).map(t => forceArray(t))
|
||||
}
|
||||
}));
|
||||
|
||||
return {
|
||||
defaultRules: rules.filter(({ tag }) => !tag),
|
||||
tagRules: rules.filter(({ tag }) => tag),
|
||||
loading,
|
||||
error,
|
||||
refetch
|
||||
};
|
||||
}
|
||||
})
|
||||
)(Firewall);
|
@ -6,12 +6,13 @@ import { ViewContainer, H2, Button, Divider } from 'joyent-ui-toolkit';
|
||||
|
||||
import Name from '@containers/create-instance/name';
|
||||
import Image from '@containers/create-instance/image';
|
||||
import Metadata from '@containers/create-instance/metadata';
|
||||
import Tags from '@containers/create-instance/tags';
|
||||
import Package from '@containers/create-instance/package';
|
||||
import Tags from '@containers/create-instance/tags';
|
||||
import Metadata from '@containers/create-instance/metadata';
|
||||
import Networks from '@containers/create-instance/networks';
|
||||
import Affinity from '@containers/create-instance/affinity';
|
||||
import Firewall from '@containers/create-instance/firewall';
|
||||
import CNS from '@containers/create-instance/cns';
|
||||
import Affinity from '@containers/create-instance/affinity';
|
||||
|
||||
export default ({ step, ...props }) => (
|
||||
<ViewContainer>
|
||||
@ -36,6 +37,9 @@ export default ({ step, ...props }) => (
|
||||
<Margin bottom={4}>
|
||||
<Networks {...props} expanded={step === 'networks'} />
|
||||
</Margin>
|
||||
<Margin bottom={5}>
|
||||
<Firewall {...props} expanded={step === 'firewall'} />
|
||||
</Margin>
|
||||
<Margin bottom={4}>
|
||||
<CNS {...props} expanded={step === 'cns'} />
|
||||
</Margin>
|
||||
|
@ -78,7 +78,7 @@ export const Networks = ({
|
||||
)}
|
||||
</ReduxForm>
|
||||
) : null}
|
||||
<div>
|
||||
<Fragment>
|
||||
{expanded ? (
|
||||
<Button type="button" onClick={handleNext}>
|
||||
Next
|
||||
@ -88,7 +88,7 @@ export const Networks = ({
|
||||
Edit
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
</Fragment>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
@ -130,7 +130,7 @@ export default compose(
|
||||
set({ name: 'create-instance-networks-proceeded', value: true })
|
||||
);
|
||||
|
||||
return history.push('/instances/~create/cns');
|
||||
return history.push('/instances/~create/firewall');
|
||||
},
|
||||
handleEdit: () => {
|
||||
return history.push('/instances/~create/networks');
|
||||
|
10
packages/my-joy-beta/src/graphql/list-fw-rules.gql
Normal file
10
packages/my-joy-beta/src/graphql/list-fw-rules.gql
Normal file
@ -0,0 +1,10 @@
|
||||
query rules($tags: [KeyValueInput]!) {
|
||||
firewall_rules_create_machine(tags: $tags) {
|
||||
id
|
||||
enabled
|
||||
rule_obj
|
||||
rule_str
|
||||
global
|
||||
tag
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user