Commit 4cc7fe06 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Merge branch 'ootb-network-policies' into 'master'

Add predefined network policies to the network policy list

See merge request gitlab-org/gitlab!36257
parents 99d9728a b36023cb
......@@ -99,6 +99,11 @@ deployment platform. Changes performed outside of this tab are
reflected upon refresh. Enforcement status changes are deployed
directly to a deployment namespace of the selected environment.
By default, the network policy list contains predefined policies in a
disabled state. Once enabled,a predefined policy deploys to the
selected environment's deployment platform and you can manage it like
the regular policies.
NOTE: **Note:**
If you're using [Auto DevOps](../../../topics/autodevops/index.md) and
change a policy in this section, your `auto-deploy-values.yaml` file
......
<script>
import { mapState, mapActions } from 'vuex';
import { mapState, mapActions, mapGetters } from 'vuex';
import {
GlTable,
GlEmptyState,
......@@ -41,6 +41,7 @@ export default {
computed: {
...mapState('networkPolicies', ['policies', 'isLoadingPolicies', 'isUpdatingPolicy']),
...mapState('threatMonitoring', ['currentEnvironmentId']),
...mapGetters('networkPolicies', ['policiesWithDefaults']),
documentationFullPath() {
return setUrlFragment(this.documentationPath, 'container-network-policy');
},
......@@ -50,7 +51,7 @@ export default {
selectedPolicy() {
if (!this.hasSelectedPolicy) return null;
return this.policies.find(policy => policy.name === this.selectedPolicyName);
return this.policiesWithDefaults.find(policy => policy.name === this.selectedPolicyName);
},
hasPolicyChanges() {
if (!this.hasSelectedPolicy) return false;
......@@ -61,12 +62,13 @@ export default {
);
},
hasAutoDevopsPolicy() {
return this.policies.some(policy => policy.isAutodevops);
return this.policiesWithDefaults.some(policy => policy.isAutodevops);
},
},
methods: {
...mapActions('networkPolicies', ['updatePolicy']),
...mapActions('networkPolicies', ['createPolicy', 'updatePolicy']),
getTimeAgoString(creationTimestamp) {
if (!creationTimestamp) return '';
return getTimeago().format(creationTimestamp);
},
presentPolicyDrawer(rows) {
......@@ -84,13 +86,19 @@ export default {
bTable.clearSelected();
},
savePolicy() {
return this.updatePolicy({
const promise = this.selectedPolicy.creationTimestamp ? this.updatePolicy : this.createPolicy;
return promise({
environmentId: this.currentEnvironmentId,
policy: this.selectedPolicy,
}).then(() => {
this.initialManifest = this.selectedPolicy.manifest;
this.initialEnforcementStatus = this.selectedPolicy.isEnabled;
});
})
.then(() => {
this.initialManifest = this.selectedPolicy.manifest;
this.initialEnforcementStatus = this.selectedPolicy.isEnabled;
})
.catch(() => {
this.selectedPolicy.manifest = this.initialManifest;
this.selectedPolicy.isEnabled = this.initialEnforcementStatus;
});
},
},
fields: [
......@@ -149,7 +157,7 @@ export default {
<gl-table
ref="policiesTable"
:busy="isLoadingPolicies"
:items="policies"
:items="policiesWithDefaults"
:fields="$options.fields"
head-variant="white"
stacked="md"
......
/* eslint-disable import/prefer-default-export */
export const INVALID_CURRENT_ENVIRONMENT_NAME = '';
export const PREDEFINED_NETWORK_POLICIES = [
{
name: 'drop-outbound',
isEnabled: false,
manifest: `---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: drop-outbound
spec:
podSelector: {}
policyTypes:
- Egress`,
},
{
name: 'allow-inbound-http',
isEnabled: false,
manifest: `---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-inbound-http
spec:
podSelector: {}
ingress:
- ports:
- port: 80
- port: 443`,
},
];
/* eslint-disable import/prefer-default-export */
import { PREDEFINED_NETWORK_POLICIES } from 'ee/threat_monitoring/constants';
export const policiesWithDefaults = ({ policies }) => {
// Predefined policies that were enabled by users will be present in
// the list of policies we received from the backend. We want to
// filter out enabled predefined policies and only append the ones
// that are not present in a cluster.
const predefined = PREDEFINED_NETWORK_POLICIES.filter(
({ name }) => !policies.some(policy => name === policy.name),
);
return [...policies, ...predefined];
};
import * as actions from './actions';
import * as getters from './getters';
import mutations from './mutations';
import state from './state';
export default () => ({
namespaced: true,
actions,
getters,
mutations,
state,
});
---
title: Add predefined network policies to the network policy list
merge_request: 36257
author:
type: added
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`NetworkPolicyList component given there is a default environment with no data to display shows the table empty state 1`] = `
<section
class="row empty-state text-center"
>
<div
class="col-12"
>
<!---->
</div>
<div
class="col-12"
>
<div
class="text-content gl-mx-auto gl-my-0 gl-p-5"
>
<h1
class="h4"
>
No policies detected
</h1>
<p>
Policies are a specification of how groups of pods are allowed to communicate with each other's network endpoints.
</p>
<div>
<a
class="btn btn-success btn-md gl-button"
href="documentation_path#container-network-policy"
>
<!---->
<!---->
<span
class="gl-button-text"
>
Learn more
</span>
</a>
<!---->
</div>
</div>
</div>
</section>
`;
exports[`NetworkPolicyList component given there is a default environment with no data to display shows the table empty state 1`] = `undefined`;
exports[`NetworkPolicyList component renders policies table 1`] = `
<table
aria-busy="false"
aria-colcount="3"
aria-describedby="__BVID__41__caption_"
aria-describedby="__BVID__45__caption_"
aria-multiselectable="false"
class="table b-table gl-table table-hover b-table-stacked-md b-table-selectable b-table-select-single"
id="__BVID__41"
id="__BVID__45"
role="table"
>
<!---->
......@@ -139,7 +90,89 @@ exports[`NetworkPolicyList component renders policies table 1`] = `
>
<div>
just now
3 months ago
</div>
</td>
</tr>
<tr
aria-selected="false"
class=""
role="row"
tabindex="0"
>
<td
aria-colindex="1"
class=""
data-label="Name"
role="cell"
>
<div>
drop-outbound
</div>
</td>
<td
aria-colindex="2"
class=""
data-label="Status"
role="cell"
>
<div>
Disabled
</div>
</td>
<td
aria-colindex="3"
class=""
data-label="Last modified"
role="cell"
>
<div>
</div>
</td>
</tr>
<tr
aria-selected="false"
class=""
role="row"
tabindex="0"
>
<td
aria-colindex="1"
class=""
data-label="Name"
role="cell"
>
<div>
allow-inbound-http
</div>
</td>
<td
aria-colindex="2"
class=""
data-label="Status"
role="cell"
>
<div>
Disabled
</div>
</td>
<td
aria-colindex="3"
class=""
data-label="Last modified"
role="cell"
>
<div>
</div>
</td>
......
......@@ -5,6 +5,7 @@ import { GlTable } from '@gitlab/ui';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { mockPoliciesResponse } from '../mock_data';
import { PREDEFINED_NETWORK_POLICIES } from 'ee/threat_monitoring/constants';
const mockData = mockPoliciesResponse.map(policy => convertObjectPropsToCamelCase(policy));
......@@ -147,6 +148,43 @@ describe('NetworkPolicyList component', () => {
policy: mockData[0],
});
});
describe('given there is an updatePolicy error', () => {
beforeEach(() => {
jest.spyOn(store, 'dispatch').mockRejectedValue();
});
it('reverts isEnabled change', () => {
const initial = mockData[0].isEnabled;
findApplyButton().vm.$emit('click');
const policyToggle = findPolicyToggle();
expect(policyToggle.exists()).toBe(true);
expect(policyToggle.props('value')).toBe(initial);
});
});
describe('given theres is a predefined policy change', () => {
beforeEach(() => {
factory({
data: () => ({
selectedPolicyName: 'drop-outbound',
initialManifest: mockData[0].manifest,
initialEnforcementStatus: mockData[0].isEnabled,
}),
});
});
it('dispatches createPolicy action on apply button click', () => {
findApplyButton().vm.$emit('click');
expect(store.dispatch).toHaveBeenCalledWith('networkPolicies/createPolicy', {
environmentId: -1,
policy: PREDEFINED_NETWORK_POLICIES[0],
});
});
});
});
describe('given there is a policy enforcement status change', () => {
......
......@@ -36,7 +36,7 @@ spec:
- namespaceSelector:
matchLabels:
project: myproject`,
created_timestamp: '2020-04-14T00:08:30Z',
creation_timestamp: '2020-04-14T00:08:30Z',
is_enabled: true,
},
];
......
import createState from 'ee/threat_monitoring/store/modules/network_policies/state';
import * as getters from 'ee/threat_monitoring/store/modules/network_policies/getters';
describe('networkPolicies module getters', () => {
let state;
beforeEach(() => {
state = createState();
});
describe('policiesWithDefaults', () => {
describe('without policies in the state', () => {
it('returns predefined policies', () => {
expect(getters.policiesWithDefaults(state).map(({ name }) => name)).toEqual([
'drop-outbound',
'allow-inbound-http',
]);
});
});
describe('with policies in the state', () => {
beforeEach(() => {
state.policies = [{ name: 'user-policy' }];
});
it('returns user owned and predefined policies', () => {
expect(getters.policiesWithDefaults(state).map(({ name }) => name)).toEqual([
'user-policy',
'drop-outbound',
'allow-inbound-http',
]);
});
describe('with deployed predefined policy', () => {
beforeEach(() => {
state.policies = [{ name: 'user-policy' }, { name: 'drop-outbound' }];
});
it('returns user policies and a single predefined policy', () => {
expect(getters.policiesWithDefaults(state).map(({ name }) => name)).toEqual([
'user-policy',
'drop-outbound',
'allow-inbound-http',
]);
});
});
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment