Commit eb3d943b authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch 'add_cilium_network_policy_into_services' into 'master'

Update controller and services NetworkPolicy related

See merge request gitlab-org/gitlab!39127
parents 5f4da7c2 beb06946
...@@ -39,9 +39,8 @@ module Projects ...@@ -39,9 +39,8 @@ module Projects
end end
def create def create
policy = Gitlab::Kubernetes::NetworkPolicy.from_yaml(params[:manifest])
response = NetworkPolicies::DeployResourceService.new( response = NetworkPolicies::DeployResourceService.new(
policy: policy, manifest: params[:manifest],
environment: environment environment: environment
).execute ).execute
...@@ -49,15 +48,11 @@ module Projects ...@@ -49,15 +48,11 @@ module Projects
end end
def update def update
policy = Gitlab::Kubernetes::NetworkPolicy.from_yaml(params[:manifest])
unless params[:enabled].nil?
params[:enabled] ? policy.enable : policy.disable
end
response = NetworkPolicies::DeployResourceService.new( response = NetworkPolicies::DeployResourceService.new(
resource_name: params[:id], resource_name: params[:id],
policy: policy, manifest: params[:manifest],
environment: environment environment: environment,
enabled: params[:enabled]
).execute ).execute
respond_with_service_response(response) respond_with_service_response(response)
...@@ -66,6 +61,7 @@ module Projects ...@@ -66,6 +61,7 @@ module Projects
def destroy def destroy
response = NetworkPolicies::DeleteResourceService.new( response = NetworkPolicies::DeleteResourceService.new(
resource_name: params[:id], resource_name: params[:id],
manifest: params[:manifest],
environment: environment environment: environment
).execute ).execute
......
...@@ -3,17 +3,24 @@ ...@@ -3,17 +3,24 @@
module NetworkPolicies module NetworkPolicies
class DeleteResourceService class DeleteResourceService
include NetworkPolicies::Responses include NetworkPolicies::Responses
include NetworkPolicies::Types
def initialize(resource_name:, environment:) def initialize(resource_name:, manifest:, environment:)
@resource_name = resource_name @resource_name = resource_name
@platform = environment.deployment_platform @platform = environment.deployment_platform
@kubernetes_namespace = environment.deployment_namespace @kubernetes_namespace = environment.deployment_namespace
@has_cilium_policy = cilium_policy?(manifest)
end end
def execute def execute
return no_platform_response unless @platform return no_platform_response unless @platform
if @has_cilium_policy
@platform.kubeclient.delete_cilium_network_policy(@resource_name, @kubernetes_namespace)
else
@platform.kubeclient.delete_network_policy(@resource_name, @kubernetes_namespace) @platform.kubeclient.delete_network_policy(@resource_name, @kubernetes_namespace)
end
ServiceResponse.success ServiceResponse.success
rescue Kubeclient::HttpError => e rescue Kubeclient::HttpError => e
kubernetes_error_response(e) kubernetes_error_response(e)
......
...@@ -3,9 +3,15 @@ ...@@ -3,9 +3,15 @@
module NetworkPolicies module NetworkPolicies
class DeployResourceService class DeployResourceService
include NetworkPolicies::Responses include NetworkPolicies::Responses
include NetworkPolicies::Types
def initialize(manifest:, environment:, resource_name: nil, enabled: nil)
@has_cilium_policy = cilium_policy?(manifest)
@policy = policy_from_manifest(manifest)
unless enabled.nil?
enabled ? policy.enable : policy.disable
end
def initialize(policy:, environment:, resource_name: nil)
@policy = policy
@platform = environment.deployment_platform @platform = environment.deployment_platform
@kubernetes_namespace = environment.deployment_namespace @kubernetes_namespace = environment.deployment_namespace
@resource_name = resource_name @resource_name = resource_name
...@@ -16,8 +22,8 @@ module NetworkPolicies ...@@ -16,8 +22,8 @@ module NetworkPolicies
return no_platform_response unless platform return no_platform_response unless platform
setup_resource setup_resource
resource = deploy_resource deploy_resource
policy = Gitlab::Kubernetes::NetworkPolicy.from_resource(resource) load_policy_from_resource
ServiceResponse.success(payload: policy) ServiceResponse.success(payload: policy)
rescue Kubeclient::HttpError => e rescue Kubeclient::HttpError => e
kubernetes_error_response(e) kubernetes_error_response(e)
...@@ -25,7 +31,7 @@ module NetworkPolicies ...@@ -25,7 +31,7 @@ module NetworkPolicies
private private
attr_reader :platform, :policy, :resource_name, :resource, :kubernetes_namespace attr_reader :platform, :policy, :resource_name, :resource, :kubernetes_namespace, :has_cilium_policy
def setup_resource def setup_resource
@resource = policy.generate @resource = policy.generate
...@@ -33,7 +39,31 @@ module NetworkPolicies ...@@ -33,7 +39,31 @@ module NetworkPolicies
resource[:metadata][:name] = resource_name if resource_name resource[:metadata][:name] = resource_name if resource_name
end end
def load_policy_from_resource
@policy = if has_cilium_policy
Gitlab::Kubernetes::CiliumNetworkPolicy.from_resource(resource)
else
Gitlab::Kubernetes::NetworkPolicy.from_resource(resource)
end
end
def deploy_resource def deploy_resource
@resource = if has_cilium_policy
deploy_cilium_network_policy
else
deploy_network_policy
end
end
def deploy_cilium_network_policy
if resource_name
platform.kubeclient.update_cilium_network_policy(resource)
else
platform.kubeclient.create_cilium_network_policy(resource)
end
end
def deploy_network_policy
if resource_name if resource_name
platform.kubeclient.update_network_policy(resource) platform.kubeclient.update_network_policy(resource)
else else
......
...@@ -15,6 +15,9 @@ module NetworkPolicies ...@@ -15,6 +15,9 @@ module NetworkPolicies
policies = @platform.kubeclient policies = @platform.kubeclient
.get_network_policies(namespace: @kubernetes_namespace) .get_network_policies(namespace: @kubernetes_namespace)
.map { |resource| Gitlab::Kubernetes::NetworkPolicy.from_resource(resource) } .map { |resource| Gitlab::Kubernetes::NetworkPolicy.from_resource(resource) }
policies += @platform.kubeclient
.get_cilium_network_policies(namespace: @kubernetes_namespace)
.map { |resource| Gitlab::Kubernetes::CiliumNetworkPolicy.from_resource(resource) }
ServiceResponse.success(payload: policies) ServiceResponse.success(payload: policies)
rescue Kubeclient::HttpError => e rescue Kubeclient::HttpError => e
kubernetes_error_response(e) kubernetes_error_response(e)
......
# frozen_string_literal: true
module NetworkPolicies
module Types
def cilium_policy?(manifest)
manifest&.include?(Gitlab::Kubernetes::CiliumNetworkPolicy::KIND)
end
def policy_from_manifest(manifest)
cilium_policy?(manifest) ? Gitlab::Kubernetes::CiliumNetworkPolicy.from_yaml(manifest) : Gitlab::Kubernetes::NetworkPolicy.from_yaml(manifest)
end
end
end
---
title: add CiliumNetworkPolicy into services
merge_request: 39127
author:
type: changed
...@@ -11,6 +11,27 @@ RSpec.describe Projects::Security::NetworkPoliciesController do ...@@ -11,6 +11,27 @@ RSpec.describe Projects::Security::NetworkPoliciesController do
let_it_be(:action_params) { { project_id: project, namespace_id: project.namespace, environment_id: environment.id } } let_it_be(:action_params) { { project_id: project, namespace_id: project.namespace, environment_id: environment.id } }
let_it_be(:manifest) do
<<~POLICY
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: example-name
namespace: example-namespace
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
project: myproject
POLICY
end
shared_examples 'CRUD service errors' do shared_examples 'CRUD service errors' do
context 'with an error service response' do context 'with an error service response' do
before do before do
...@@ -189,33 +210,12 @@ RSpec.describe Projects::Security::NetworkPoliciesController do ...@@ -189,33 +210,12 @@ RSpec.describe Projects::Security::NetworkPoliciesController do
) )
end end
let(:manifest) do
<<~POLICY
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: example-name
namespace: example-namespace
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
project: myproject
POLICY
end
context 'with authorized user' do context 'with authorized user' do
before do before do
group.add_developer(user) group.add_developer(user)
allow(NetworkPolicies::DeployResourceService).to( allow(NetworkPolicies::DeployResourceService).to(
receive(:new) receive(:new)
.with(policy: kind_of(Gitlab::Kubernetes::NetworkPolicy), environment: environment) .with(manifest: manifest, environment: environment)
.and_return(service) .and_return(service)
) )
end end
...@@ -253,33 +253,12 @@ RSpec.describe Projects::Security::NetworkPoliciesController do ...@@ -253,33 +253,12 @@ RSpec.describe Projects::Security::NetworkPoliciesController do
) )
end end
let(:manifest) do
<<~POLICY
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: example-name
namespace: example-namespace
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
project: myproject
POLICY
end
context 'with authorized user' do context 'with authorized user' do
before do before do
group.add_developer(user) group.add_developer(user)
allow(NetworkPolicies::DeployResourceService).to( allow(NetworkPolicies::DeployResourceService).to(
receive(:new) receive(:new)
.with(policy: kind_of(Gitlab::Kubernetes::NetworkPolicy), environment: environment, resource_name: 'example-policy') .with(manifest: manifest, environment: environment, enabled: enabled, resource_name: 'example-policy')
.and_return(service) .and_return(service)
) )
end end
...@@ -292,34 +271,6 @@ RSpec.describe Projects::Security::NetworkPoliciesController do ...@@ -292,34 +271,6 @@ RSpec.describe Projects::Security::NetworkPoliciesController do
end end
include_examples 'CRUD service errors' include_examples 'CRUD service errors'
context 'with enabled param' do
let(:enabled) { true }
before do
allow(Gitlab::Kubernetes::NetworkPolicy).to receive(:new) { policy }
end
it 'enables policy and responds with success' do
expect(policy).to receive(:enable)
subject
expect(response).to have_gitlab_http_status(:success)
end
context 'with enabled=false' do
let(:enabled) { false }
it 'disables policy and responds with success' do
expect(policy).to receive(:disable)
subject
expect(response).to have_gitlab_http_status(:success)
end
end
end
end end
context 'with unauthorized user' do context 'with unauthorized user' do
...@@ -332,7 +283,7 @@ RSpec.describe Projects::Security::NetworkPoliciesController do ...@@ -332,7 +283,7 @@ RSpec.describe Projects::Security::NetworkPoliciesController do
end end
describe 'DELETE #destroy' do describe 'DELETE #destroy' do
subject { delete :destroy, params: action_params.merge(id: 'example-policy'), format: :json } subject { delete :destroy, params: action_params.merge(id: 'example-policy', manifest: manifest), format: :json }
let(:service) { instance_double('NetworkPolicies::DeleteResourceService', execute: ServiceResponse.success) } let(:service) { instance_double('NetworkPolicies::DeleteResourceService', execute: ServiceResponse.success) }
...@@ -341,7 +292,7 @@ RSpec.describe Projects::Security::NetworkPoliciesController do ...@@ -341,7 +292,7 @@ RSpec.describe Projects::Security::NetworkPoliciesController do
group.add_developer(user) group.add_developer(user)
allow(NetworkPolicies::DeleteResourceService).to( allow(NetworkPolicies::DeleteResourceService).to(
receive(:new) receive(:new)
.with(environment: environment, resource_name: 'example-policy') .with(environment: environment, manifest: manifest, resource_name: 'example-policy')
.and_return(service) .and_return(service)
) )
end end
......
...@@ -3,10 +3,32 @@ ...@@ -3,10 +3,32 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe NetworkPolicies::DeleteResourceService do RSpec.describe NetworkPolicies::DeleteResourceService do
let(:service) { NetworkPolicies::DeleteResourceService.new(resource_name: 'policy', environment: environment) } let(:service) { NetworkPolicies::DeleteResourceService.new(resource_name: 'policy', environment: environment, manifest: manifest) }
let(:environment) { instance_double('Environment', deployment_platform: platform, deployment_namespace: 'namespace') } let(:environment) { instance_double('Environment', deployment_platform: platform, deployment_namespace: 'namespace') }
let(:platform) { instance_double('Clusters::Platforms::Kubernetes', kubeclient: kubeclient) } let(:platform) { instance_double('Clusters::Platforms::Kubernetes', kubeclient: kubeclient) }
let(:kubeclient) { double('Kubeclient::Client') } let(:kubeclient) { double('Kubeclient::Client') }
let(:manifest) do
<<~POLICY
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: example-name
namespace: example-namespace
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
project: myproject
POLICY
end
include_examples 'different network policy types'
describe '#execute' do describe '#execute' do
subject { service.execute } subject { service.execute }
...@@ -37,5 +59,31 @@ RSpec.describe NetworkPolicies::DeleteResourceService do ...@@ -37,5 +59,31 @@ RSpec.describe NetworkPolicies::DeleteResourceService do
expect(subject.message).not_to be_nil expect(subject.message).not_to be_nil
end end
end end
context 'with CiliumNetworkPolicy' do
let(:manifest) do
<<~POLICY
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: example-name
namespace: example-namespace
resourceVersion: 101
spec:
endpointSelector:
matchLabels:
role: db
ingress:
- fromEndpoints:
- matchLabels:
project: myproject
POLICY
end
it 'deletes resource from the deployment namespace and returns success response' do
expect(kubeclient).to receive(:delete_cilium_network_policy).with('policy', environment.deployment_namespace)
expect(subject).to be_success
end
end
end end
end end
...@@ -3,10 +3,12 @@ ...@@ -3,10 +3,12 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe NetworkPolicies::DeployResourceService do RSpec.describe NetworkPolicies::DeployResourceService do
let(:service) { NetworkPolicies::DeployResourceService.new(policy: policy, environment: environment) } let(:service) { NetworkPolicies::DeployResourceService.new(resource_name: resource_name, manifest: manifest, environment: environment, enabled: enabled) }
let(:environment) { instance_double('Environment', deployment_platform: platform, deployment_namespace: 'namespace') } let(:environment) { instance_double('Environment', deployment_platform: platform, deployment_namespace: 'namespace') }
let(:platform) { instance_double('Clusters::Platforms::Kubernetes', kubeclient: kubeclient) } let(:platform) { instance_double('Clusters::Platforms::Kubernetes', kubeclient: kubeclient) }
let(:kubeclient) { double('Kubeclient::Client') } let(:kubeclient) { double('Kubeclient::Client') }
let(:enabled) { nil }
let(:resource_name) { nil }
let(:policy) do let(:policy) do
Gitlab::Kubernetes::NetworkPolicy.new( Gitlab::Kubernetes::NetworkPolicy.new(
name: 'policy', name: 'policy',
...@@ -16,6 +18,34 @@ RSpec.describe NetworkPolicies::DeployResourceService do ...@@ -16,6 +18,34 @@ RSpec.describe NetworkPolicies::DeployResourceService do
) )
end end
let(:manifest) do
<<~POLICY
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: policy
namespace: another
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
project: myproject
POLICY
end
include_examples 'different network policy types'
before do
allow(Gitlab::Kubernetes::NetworkPolicy).to receive(:from_resource).and_return policy
allow(Gitlab::Kubernetes::NetworkPolicy).to receive(:from_yaml).and_return policy
end
describe '#execute' do describe '#execute' do
subject { service.execute } subject { service.execute }
...@@ -29,7 +59,7 @@ RSpec.describe NetworkPolicies::DeployResourceService do ...@@ -29,7 +59,7 @@ RSpec.describe NetworkPolicies::DeployResourceService do
end end
context 'with resource_name' do context 'with resource_name' do
let(:service) { NetworkPolicies::DeployResourceService.new(policy: policy, environment: environment, resource_name: 'policy2') } let(:resource_name) { 'policy2' }
it 'updates resource in the deployment namespace and returns success response with a policy' do it 'updates resource in the deployment namespace and returns success response with a policy' do
namespaced_policy = policy.generate namespaced_policy = policy.generate
...@@ -42,7 +72,8 @@ RSpec.describe NetworkPolicies::DeployResourceService do ...@@ -42,7 +72,8 @@ RSpec.describe NetworkPolicies::DeployResourceService do
end end
end end
context 'without policy' do context 'without manifest' do
let(:manifest) { nil }
let(:policy) { nil } let(:policy) { nil }
it 'returns error response' do it 'returns error response' do
...@@ -73,5 +104,79 @@ RSpec.describe NetworkPolicies::DeployResourceService do ...@@ -73,5 +104,79 @@ RSpec.describe NetworkPolicies::DeployResourceService do
expect(subject.message).not_to be_nil expect(subject.message).not_to be_nil
end end
end end
context 'with cilium network policy' do
let(:manifest) do
<<~POLICY
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: policy
namespace: another
resourceVersion: 101
spec:
endpointSelector:
matchLabels:
role: db
ingress:
- fromEndpoints:
- matchLabels:
project: myproject
POLICY
end
let(:policy) do
Gitlab::Kubernetes::CiliumNetworkPolicy.new(
name: 'policy',
namespace: 'namespace',
resource_version: 101,
selector: { matchLabels: { role: 'db' } },
ingress: [{ fromEndpoints: [{ matchLabels: { project: 'myproject' } }] }]
)
end
it 'creates resource in the deployment namespace and return success response with a policy' do
namespaced_policy = policy.generate
namespaced_policy[:metadata][:namespace] = environment.deployment_namespace
expect(kubeclient).to receive(:create_cilium_network_policy).with(namespaced_policy) { policy.generate }
expect(subject).to be_success
expect(subject.payload.as_json).to eq(policy.as_json)
end
context 'with resource_name' do
let(:resource_name) { 'policy' }
it 'updates resource in the deployment namespace and returns success response with a policy' do
namespaced_policy = policy.generate
namespaced_policy[:metadata][:namespace] = environment.deployment_namespace
namespaced_policy[:metadata][:name] = resource_name
expect(kubeclient).to receive(:update_cilium_network_policy).with(namespaced_policy) { policy.generate }
expect(subject).to be_success
expect(subject.payload.as_json).to eq(policy.as_json)
end
end
end
context 'with enabled set to true' do
let(:enabled) { true }
it 'enables policy before deploying it' do
expect(policy).to receive(:enable)
expect(kubeclient).to receive(:create_network_policy) { policy.generate }
expect(subject).to be_success
end
end
context 'with enabled set to false' do
let(:enabled) { false }
it 'disables policy before deploying it' do
expect(policy).to receive(:disable)
expect(kubeclient).to receive(:create_network_policy) { policy.generate }
expect(subject).to be_success
end
end
end end
end end
...@@ -16,14 +16,26 @@ RSpec.describe NetworkPolicies::ResourcesService do ...@@ -16,14 +16,26 @@ RSpec.describe NetworkPolicies::ResourcesService do
) )
end end
let(:cilium_policy) do
Gitlab::Kubernetes::CiliumNetworkPolicy.new(
name: 'cilium_policy',
namespace: 'another',
resource_version: '102',
selector: { matchLabels: { role: 'db' } },
ingress: [{ endpointFrom: [{ matchLabels: { project: 'myproject' } }] }]
)
end
describe '#execute' do describe '#execute' do
subject { service.execute } subject { service.execute }
it 'returns success response with policies from the deployment namespace' do it 'returns success response with policies from the deployment namespace' do
expect(kubeclient).to receive(:get_network_policies).with(namespace: environment.deployment_namespace) { [policy.generate] } expect(kubeclient).to receive(:get_network_policies).with(namespace: environment.deployment_namespace) { [policy.generate] }
expect(kubeclient).to receive(:get_cilium_network_policies).with(namespace: environment.deployment_namespace) { [cilium_policy.generate] }
expect(subject).to be_success expect(subject).to be_success
expect(subject.payload.count).to eq(1) expect(subject.payload.count).to eq(2)
expect(subject.payload.first.as_json).to eq(policy.as_json) expect(subject.payload.first.as_json).to eq(policy.as_json)
expect(subject.payload.last.as_json).to eq(cilium_policy.as_json)
end end
context 'without deployment_platform' do context 'without deployment_platform' do
......
# frozen_string_literal: true
RSpec.shared_examples 'different network policy types' do
let(:network_policy_manifest) do
<<~POLICY
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: example-name
namespace: example-namespace
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
project: myproject
POLICY
end
let(:cilium_network_policy_manifest) do
<<~POLICY
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: example-name
namespace: example-namespace
resourceVersion: 101
spec:
endpointSelector:
matchLabels:
role: db
ingress:
- fromEndpoints:
- matchLabels:
project: myproject
POLICY
end
describe 'cilium_policy?' do
subject { service.cilium_policy?(manifest) }
context 'with nil as parameter' do
let(:manifest) { nil }
it { is_expected.to be_nil }
end
context 'with a manifest of NetworkPolicy' do
let(:manifest) { network_policy_manifest }
it { is_expected.to be false }
end
context 'with a manifest of CiliumNetworkPolicy' do
let(:manifest) { cilium_network_policy_manifest }
it { is_expected.to be true }
end
end
describe 'policy_from_manifest' do
subject { service.policy_from_manifest(manifest) }
context 'with a manifest of a NetworkPolicy' do
let(:manifest) { network_policy_manifest }
it { is_expected.to be_an_instance_of Gitlab::Kubernetes::NetworkPolicy }
end
context 'with a manifest of a CiliumNetworkPolicy' do
let(:manifest) { cilium_network_policy_manifest }
it { is_expected.to be_an_instance_of Gitlab::Kubernetes::CiliumNetworkPolicy }
end
end
end
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