Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Léo-Paul Géneau
gitlab-ce
Commits
5ede567d
Commit
5ede567d
authored
6 years ago
by
Thong Kuah
Committed by
Kamil Trzciński
6 years ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Incorporates Kubernetes Namespace into Cluster's flow
parent
2a89f065
Changes
33
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
873 additions
and
341 deletions
+873
-341
app/models/clusters/cluster.rb
app/models/clusters/cluster.rb
+8
-0
app/models/clusters/kubernetes_namespace.rb
app/models/clusters/kubernetes_namespace.rb
+29
-6
app/models/clusters/platforms/kubernetes.rb
app/models/clusters/platforms/kubernetes.rb
+28
-8
app/models/project.rb
app/models/project.rb
+1
-1
app/models/project_services/kubernetes_service.rb
app/models/project_services/kubernetes_service.rb
+6
-1
app/services/clusters/gcp/finalize_creation_service.rb
app/services/clusters/gcp/finalize_creation_service.rb
+20
-3
app/services/clusters/gcp/kubernetes.rb
app/services/clusters/gcp/kubernetes.rb
+6
-5
app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb
...ters/gcp/kubernetes/create_or_update_namespace_service.rb
+54
-0
app/services/clusters/gcp/kubernetes/create_service_account_service.rb
...clusters/gcp/kubernetes/create_service_account_service.rb
+64
-14
app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb
...clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb
+5
-3
app/workers/all_queues.yml
app/workers/all_queues.yml
+1
-0
app/workers/cluster_platform_configure_worker.rb
app/workers/cluster_platform_configure_worker.rb
+22
-0
app/workers/cluster_provision_worker.rb
app/workers/cluster_provision_worker.rb
+2
-0
changelogs/unreleased/51716-create-kube-namespace.yml
changelogs/unreleased/51716-create-kube-namespace.yml
+5
-0
lib/gitlab/kubernetes/role_binding.rb
lib/gitlab/kubernetes/role_binding.rb
+6
-5
spec/controllers/projects/clusters_controller_spec.rb
spec/controllers/projects/clusters_controller_spec.rb
+11
-0
spec/factories/clusters/kubernetes_namespaces.rb
spec/factories/clusters/kubernetes_namespaces.rb
+13
-3
spec/features/projects/clusters/gcp_spec.rb
spec/features/projects/clusters/gcp_spec.rb
+1
-0
spec/features/projects/clusters/user_spec.rb
spec/features/projects/clusters/user_spec.rb
+2
-0
spec/lib/gitlab/kubernetes/role_binding_spec.rb
spec/lib/gitlab/kubernetes/role_binding_spec.rb
+2
-1
spec/models/clusters/applications/prometheus_spec.rb
spec/models/clusters/applications/prometheus_spec.rb
+8
-2
spec/models/clusters/cluster_spec.rb
spec/models/clusters/cluster_spec.rb
+1
-0
spec/models/clusters/kubernetes_namespace_spec.rb
spec/models/clusters/kubernetes_namespace_spec.rb
+54
-31
spec/models/clusters/platforms/kubernetes_spec.rb
spec/models/clusters/platforms/kubernetes_spec.rb
+34
-25
spec/models/project_services/kubernetes_service_spec.rb
spec/models/project_services/kubernetes_service_spec.rb
+3
-3
spec/models/project_spec.rb
spec/models/project_spec.rb
+13
-1
spec/services/clusters/gcp/finalize_creation_service_spec.rb
spec/services/clusters/gcp/finalize_creation_service_spec.rb
+149
-129
spec/services/clusters/gcp/kubernetes/create_or_update_namespace_service_spec.rb
...gcp/kubernetes/create_or_update_namespace_service_spec.rb
+115
-0
spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb
...ers/gcp/kubernetes/create_service_account_service_spec.rb
+141
-70
spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb
...ers/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb
+21
-29
spec/services/clusters/update_service_spec.rb
spec/services/clusters/update_service_spec.rb
+7
-0
spec/workers/cluster_platform_configure_worker_spec.rb
spec/workers/cluster_platform_configure_worker_spec.rb
+33
-0
spec/workers/cluster_provision_worker_spec.rb
spec/workers/cluster_provision_worker_spec.rb
+8
-1
No files found.
app/models/clusters/cluster.rb
View file @
5ede567d
...
...
@@ -19,6 +19,7 @@ module Clusters
has_many
:cluster_projects
,
class_name:
'Clusters::Project'
has_many
:projects
,
through: :cluster_projects
,
class_name:
'::Project'
has_one
:cluster_project
,
->
{
order
(
id: :desc
)
},
class_name:
'Clusters::Project'
has_many
:cluster_groups
,
class_name:
'Clusters::Group'
has_many
:groups
,
through: :cluster_groups
,
class_name:
'::Group'
...
...
@@ -128,6 +129,13 @@ module Clusters
platform_kubernetes
.
kubeclient
if
kubernetes?
end
def
find_or_initialize_kubernetes_namespace
(
cluster_project
)
kubernetes_namespaces
.
find_or_initialize_by
(
project:
cluster_project
.
project
,
cluster_project:
cluster_project
)
end
private
def
restrict_modification
...
...
This diff is collapsed.
Click to expand it.
app/models/clusters/kubernetes_namespace.rb
View file @
5ede567d
...
...
@@ -2,6 +2,8 @@
module
Clusters
class
KubernetesNamespace
<
ActiveRecord
::
Base
include
Gitlab
::
Kubernetes
self
.
table_name
=
'clusters_kubernetes_namespaces'
belongs_to
:cluster_project
,
class_name:
'Clusters::Project'
...
...
@@ -12,7 +14,8 @@ module Clusters
validates
:namespace
,
presence:
true
validates
:namespace
,
uniqueness:
{
scope: :cluster_id
}
before_validation
:set_namespace_and_service_account_to_default
,
on: :create
delegate
:ca_pem
,
to: :platform_kubernetes
,
allow_nil:
true
delegate
:api_url
,
to: :platform_kubernetes
,
allow_nil:
true
attr_encrypted
:service_account_token
,
mode: :per_attribute_iv
,
...
...
@@ -23,14 +26,26 @@ module Clusters
"
#{
namespace
}
-token"
end
private
def
configure_predefined_credentials
self
.
namespace
=
kubernetes_or_project_namespace
self
.
service_account_name
=
default_service_account_name
end
def
predefined_variables
config
=
YAML
.
dump
(
kubeconfig
)
def
set_namespace_and_service_account_to_default
self
.
namespace
||=
default_namespace
self
.
service_account_name
||=
default_service_account_name
Gitlab
::
Ci
::
Variables
::
Collection
.
new
.
tap
do
|
variables
|
variables
.
append
(
key:
'KUBE_SERVICE_ACCOUNT'
,
value:
service_account_name
)
.
append
(
key:
'KUBE_NAMESPACE'
,
value:
namespace
)
.
append
(
key:
'KUBE_TOKEN'
,
value:
service_account_token
,
public:
false
)
.
append
(
key:
'KUBECONFIG'
,
value:
config
,
public:
false
,
file:
true
)
end
end
def
default_namespace
private
def
kubernetes_or_project_namespace
platform_kubernetes
&
.
namespace
.
presence
||
project_namespace
end
...
...
@@ -45,5 +60,13 @@ module Clusters
def
project_slug
"
#{
project
.
path
}
-
#{
project
.
id
}
"
.
downcase
end
def
kubeconfig
to_kubeconfig
(
url:
api_url
,
namespace:
namespace
,
token:
service_account_token
,
ca_pem:
ca_pem
)
end
end
end
This diff is collapsed.
Click to expand it.
app/models/clusters/platforms/kubernetes.rb
View file @
5ede567d
...
...
@@ -6,6 +6,7 @@ module Clusters
include
Gitlab
::
Kubernetes
include
ReactiveCaching
include
EnumWithNil
include
AfterCommitQueue
RESERVED_NAMESPACES
=
%w(gitlab-managed-apps)
.
freeze
...
...
@@ -43,6 +44,7 @@ module Clusters
validate
:prevent_modification
,
on: :update
after_save
:clear_reactive_cache!
after_update
:update_kubernetes_namespace
alias_attribute
:ca_pem
,
:ca_cert
...
...
@@ -67,21 +69,31 @@ module Clusters
end
end
def
predefined_variables
config
=
YAML
.
dump
(
kubeconfig
)
def
predefined_variables
(
project
:)
Gitlab
::
Ci
::
Variables
::
Collection
.
new
.
tap
do
|
variables
|
variables
.
append
(
key:
'KUBE_URL'
,
value:
api_url
)
.
append
(
key:
'KUBE_TOKEN'
,
value:
token
,
public:
false
)
.
append
(
key:
'KUBE_NAMESPACE'
,
value:
actual_namespace
)
.
append
(
key:
'KUBECONFIG'
,
value:
config
,
public:
false
,
file:
true
)
variables
.
append
(
key:
'KUBE_URL'
,
value:
api_url
)
if
ca_pem
.
present?
variables
.
append
(
key:
'KUBE_CA_PEM'
,
value:
ca_pem
)
.
append
(
key:
'KUBE_CA_PEM_FILE'
,
value:
ca_pem
,
file:
true
)
end
if
kubernetes_namespace
=
cluster
.
kubernetes_namespaces
.
find_by
(
project:
project
)
variables
.
concat
(
kubernetes_namespace
.
predefined_variables
)
else
# From 11.5, every Clusters::Project should have at least one
# Clusters::KubernetesNamespace, so once migration has been completed,
# this 'else' branch will be removed. For more information, please see
# https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22433
config
=
YAML
.
dump
(
kubeconfig
)
variables
.
append
(
key:
'KUBE_URL'
,
value:
api_url
)
.
append
(
key:
'KUBE_TOKEN'
,
value:
token
,
public:
false
)
.
append
(
key:
'KUBE_NAMESPACE'
,
value:
actual_namespace
)
.
append
(
key:
'KUBECONFIG'
,
value:
config
,
public:
false
,
file:
true
)
end
end
end
...
...
@@ -199,6 +211,14 @@ module Clusters
true
end
def
update_kubernetes_namespace
return
unless
namespace_changed?
run_after_commit
do
ClusterPlatformConfigureWorker
.
perform_async
(
cluster_id
)
end
end
end
end
end
This diff is collapsed.
Click to expand it.
app/models/project.rb
View file @
5ede567d
...
...
@@ -1829,7 +1829,7 @@ class Project < ActiveRecord::Base
end
def
deployment_variables
(
environment:
nil
)
deployment_platform
(
environment:
environment
)
&
.
predefined_variables
||
[]
deployment_platform
(
environment:
environment
)
&
.
predefined_variables
(
project:
self
)
||
[]
end
def
auto_devops_variables
...
...
This diff is collapsed.
Click to expand it.
app/models/project_services/kubernetes_service.rb
View file @
5ede567d
...
...
@@ -104,7 +104,12 @@ class KubernetesService < DeploymentService
{
success:
false
,
result:
err
}
end
def
predefined_variables
# Project param was added on
# https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22011,
# as a way to keep this service compatible with
# Clusters::Platforms::Kubernetes, it won't be used on this method
# as it's only needed for Clusters::Cluster.
def
predefined_variables
(
project
:)
config
=
YAML
.
dump
(
kubeconfig
)
Gitlab
::
Ci
::
Variables
::
Collection
.
new
.
tap
do
|
variables
|
...
...
This diff is collapsed.
Click to expand it.
app/services/clusters/gcp/finalize_creation_service.rb
View file @
5ede567d
...
...
@@ -11,8 +11,9 @@ module Clusters
configure_provider
create_gitlab_service_account!
configure_kubernetes
cluster
.
save!
configure_project_service_account
rescue
Google
::
Apis
::
ServerError
,
Google
::
Apis
::
ClientError
,
Google
::
Apis
::
AuthorizationError
=>
e
provider
.
make_errored!
(
"Failed to request to CloudPlatform;
#{
e
.
message
}
"
)
rescue
Kubeclient
::
HttpError
=>
e
...
...
@@ -24,7 +25,10 @@ module Clusters
private
def
create_gitlab_service_account!
Clusters
::
Gcp
::
Kubernetes
::
CreateServiceAccountService
.
new
(
kube_client
,
rbac:
create_rbac_cluster?
).
execute
Clusters
::
Gcp
::
Kubernetes
::
CreateServiceAccountService
.
gitlab_creator
(
kube_client
,
rbac:
create_rbac_cluster?
).
execute
end
def
configure_provider
...
...
@@ -44,7 +48,20 @@ module Clusters
end
def
request_kubernetes_token
Clusters
::
Gcp
::
Kubernetes
::
FetchKubernetesTokenService
.
new
(
kube_client
).
execute
Clusters
::
Gcp
::
Kubernetes
::
FetchKubernetesTokenService
.
new
(
kube_client
,
Clusters
::
Gcp
::
Kubernetes
::
GITLAB_ADMIN_TOKEN_NAME
,
Clusters
::
Gcp
::
Kubernetes
::
GITLAB_SERVICE_ACCOUNT_NAMESPACE
).
execute
end
def
configure_project_service_account
kubernetes_namespace
=
cluster
.
find_or_initialize_kubernetes_namespace
(
cluster
.
cluster_project
)
Clusters
::
Gcp
::
Kubernetes
::
CreateOrUpdateNamespaceService
.
new
(
cluster:
cluster
,
kubernetes_namespace:
kubernetes_namespace
).
execute
end
def
authorization_type
...
...
This diff is collapsed.
Click to expand it.
app/services/clusters/gcp/kubernetes.rb
View file @
5ede567d
...
...
@@ -3,11 +3,12 @@
module
Clusters
module
Gcp
module
Kubernetes
SERVICE_ACCOUNT_NAME
=
'gitlab'
SERVICE_ACCOUNT_NAMESPACE
=
'default'
SERVICE_ACCOUNT_TOKEN_NAME
=
'gitlab-token'
CLUSTER_ROLE_BINDING_NAME
=
'gitlab-admin'
CLUSTER_ROLE_NAME
=
'cluster-admin'
GITLAB_SERVICE_ACCOUNT_NAME
=
'gitlab'
GITLAB_SERVICE_ACCOUNT_NAMESPACE
=
'default'
GITLAB_ADMIN_TOKEN_NAME
=
'gitlab-token'
GITLAB_CLUSTER_ROLE_BINDING_NAME
=
'gitlab-admin'
GITLAB_CLUSTER_ROLE_NAME
=
'cluster-admin'
PROJECT_CLUSTER_ROLE_NAME
=
'edit'
end
end
end
This diff is collapsed.
Click to expand it.
app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb
0 → 100644
View file @
5ede567d
# frozen_string_literal: true
module
Clusters
module
Gcp
module
Kubernetes
class
CreateOrUpdateNamespaceService
def
initialize
(
cluster
:,
kubernetes_namespace
:)
@cluster
=
cluster
@kubernetes_namespace
=
kubernetes_namespace
@platform
=
cluster
.
platform
end
def
execute
configure_kubernetes_namespace
create_project_service_account
configure_kubernetes_token
kubernetes_namespace
.
save!
rescue
::
Kubeclient
::
HttpError
=>
err
raise
err
unless
err
.
error_code
=
404
end
private
attr_reader
:cluster
,
:kubernetes_namespace
,
:platform
def
configure_kubernetes_namespace
kubernetes_namespace
.
configure_predefined_credentials
end
def
create_project_service_account
Clusters
::
Gcp
::
Kubernetes
::
CreateServiceAccountService
.
namespace_creator
(
platform
.
kubeclient
,
service_account_name:
kubernetes_namespace
.
service_account_name
,
service_account_namespace:
kubernetes_namespace
.
namespace
,
rbac:
platform
.
rbac?
).
execute
end
def
configure_kubernetes_token
kubernetes_namespace
.
service_account_token
=
fetch_service_account_token
end
def
fetch_service_account_token
Clusters
::
Gcp
::
Kubernetes
::
FetchKubernetesTokenService
.
new
(
platform
.
kubeclient
,
kubernetes_namespace
.
token_name
,
kubernetes_namespace
.
namespace
).
execute
end
end
end
end
end
This diff is collapsed.
Click to expand it.
app/services/clusters/gcp/kubernetes/create_service_account_service.rb
View file @
5ede567d
...
...
@@ -4,46 +4,96 @@ module Clusters
module
Gcp
module
Kubernetes
class
CreateServiceAccountService
attr_reader
:kubeclient
,
:rbac
def
initialize
(
kubeclient
,
rbac
:)
def
initialize
(
kubeclient
,
service_account_name
:,
service_account_namespace
:,
token_name
:,
rbac
:,
namespace_creator:
false
,
role_binding_name:
nil
)
@kubeclient
=
kubeclient
@service_account_name
=
service_account_name
@service_account_namespace
=
service_account_namespace
@token_name
=
token_name
@rbac
=
rbac
@namespace_creator
=
namespace_creator
@role_binding_name
=
role_binding_name
end
def
self
.
gitlab_creator
(
kubeclient
,
rbac
:)
self
.
new
(
kubeclient
,
service_account_name:
Clusters
::
Gcp
::
Kubernetes
::
GITLAB_SERVICE_ACCOUNT_NAME
,
service_account_namespace:
Clusters
::
Gcp
::
Kubernetes
::
GITLAB_SERVICE_ACCOUNT_NAMESPACE
,
token_name:
Clusters
::
Gcp
::
Kubernetes
::
GITLAB_ADMIN_TOKEN_NAME
,
rbac:
rbac
)
end
def
self
.
namespace_creator
(
kubeclient
,
service_account_name
:,
service_account_namespace
:,
rbac
:)
self
.
new
(
kubeclient
,
service_account_name:
service_account_name
,
service_account_namespace:
service_account_namespace
,
token_name:
"
#{
service_account_namespace
}
-token"
,
rbac:
rbac
,
namespace_creator:
true
,
role_binding_name:
"gitlab-
#{
service_account_namespace
}
"
)
end
def
execute
ensure_project_namespace_exists
if
namespace_creator
kubeclient
.
create_service_account
(
service_account_resource
)
kubeclient
.
create_secret
(
service_account_token_resource
)
kubeclient
.
create_cluster_role_binding
(
cluster_role_binding_resource
)
if
rbac
create_role_or_cluster_role_binding
if
rbac
end
private
attr_reader
:kubeclient
,
:service_account_name
,
:service_account_namespace
,
:token_name
,
:rbac
,
:namespace_creator
,
:role_binding_name
def
ensure_project_namespace_exists
Gitlab
::
Kubernetes
::
Namespace
.
new
(
service_account_namespace
,
kubeclient
).
ensure_exists!
end
def
create_role_or_cluster_role_binding
if
namespace_creator
kubeclient
.
create_role_binding
(
role_binding_resource
)
else
kubeclient
.
create_cluster_role_binding
(
cluster_role_binding_resource
)
end
end
def
service_account_resource
Gitlab
::
Kubernetes
::
ServiceAccount
.
new
(
service_account_name
,
service_account_namespace
).
generate
Gitlab
::
Kubernetes
::
ServiceAccount
.
new
(
service_account_name
,
service_account_namespace
).
generate
end
def
service_account_token_resource
Gitlab
::
Kubernetes
::
ServiceAccountToken
.
new
(
SERVICE_ACCOUNT_TOKEN_NAME
,
service_account_name
,
service_account_namespace
).
generate
token_name
,
service_account_name
,
service_account_namespace
).
generate
end
def
cluster_role_binding_resource
subjects
=
[{
kind:
'ServiceAccount'
,
name:
service_account_name
,
namespace:
service_account_namespace
}]
Gitlab
::
Kubernetes
::
ClusterRoleBinding
.
new
(
CLUSTER_ROLE_BINDING_NAME
,
CLUSTER_ROLE_NAME
,
C
lusters
::
Gcp
::
Kubernetes
::
GITLAB_C
LUSTER_ROLE_BINDING_NAME
,
C
lusters
::
Gcp
::
Kubernetes
::
GITLAB_C
LUSTER_ROLE_NAME
,
subjects
).
generate
end
def
service_account_name
SERVICE_ACCOUNT_NAME
end
def
service_account_namespace
SERVICE_ACCOUNT_NAMESPACE
def
role_binding_resource
Gitlab
::
Kubernetes
::
RoleBinding
.
new
(
name:
role_binding_name
,
role_name:
Clusters
::
Gcp
::
Kubernetes
::
PROJECT_CLUSTER_ROLE_NAME
,
namespace:
service_account_namespace
,
service_account_name:
service_account_name
).
generate
end
end
end
...
...
This diff is collapsed.
Click to expand it.
app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb
View file @
5ede567d
...
...
@@ -4,10 +4,12 @@ module Clusters
module
Gcp
module
Kubernetes
class
FetchKubernetesTokenService
attr_reader
:kubeclient
attr_reader
:kubeclient
,
:service_account_token_name
,
:namespace
def
initialize
(
kubeclient
)
def
initialize
(
kubeclient
,
service_account_token_name
,
namespace
)
@kubeclient
=
kubeclient
@service_account_token_name
=
service_account_token_name
@namespace
=
namespace
end
def
execute
...
...
@@ -18,7 +20,7 @@ module Clusters
private
def
get_secret
kubeclient
.
get_secret
(
SERVICE_ACCOUNT_TOKEN_NAME
,
SERVICE_ACCOUNT_NAMESPACE
).
as_json
kubeclient
.
get_secret
(
service_account_token_name
,
namespace
).
as_json
rescue
Kubeclient
::
HttpError
=>
err
raise
err
unless
err
.
error_code
==
404
...
...
This diff is collapsed.
Click to expand it.
app/workers/all_queues.yml
View file @
5ede567d
...
...
@@ -28,6 +28,7 @@
-
gcp_cluster:cluster_wait_for_app_installation
-
gcp_cluster:wait_for_cluster_creation
-
gcp_cluster:cluster_wait_for_ingress_ip_address
-
gcp_cluster:cluster_platform_configure
-
github_import_advance_stage
-
github_importer:github_import_import_diff_note
...
...
This diff is collapsed.
Click to expand it.
app/workers/cluster_platform_configure_worker.rb
0 → 100644
View file @
5ede567d
# frozen_string_literal: true
class
ClusterPlatformConfigureWorker
include
ApplicationWorker
include
ClusterQueue
def
perform
(
cluster_id
)
Clusters
::
Cluster
.
find_by_id
(
cluster_id
).
try
do
|
cluster
|
next
unless
cluster
.
cluster_project
kubernetes_namespace
=
cluster
.
find_or_initialize_kubernetes_namespace
(
cluster
.
cluster_project
)
Clusters
::
Gcp
::
Kubernetes
::
CreateOrUpdateNamespaceService
.
new
(
cluster:
cluster
,
kubernetes_namespace:
kubernetes_namespace
).
execute
end
rescue
::
Kubeclient
::
HttpError
=>
err
Rails
.
logger
.
error
"Failed to create/update Kubernetes Namespace. id:
#{
kubernetes_namespace
.
id
}
message:
#{
err
.
message
}
"
end
end
This diff is collapsed.
Click to expand it.
app/workers/cluster_provision_worker.rb
View file @
5ede567d
...
...
@@ -9,6 +9,8 @@ class ClusterProvisionWorker
cluster
.
provider
.
try
do
|
provider
|
Clusters
::
Gcp
::
ProvisionService
.
new
.
execute
(
provider
)
if
cluster
.
gcp?
end
ClusterPlatformConfigureWorker
.
perform_async
(
cluster
.
id
)
if
cluster
.
user?
end
end
end
This diff is collapsed.
Click to expand it.
changelogs/unreleased/51716-create-kube-namespace.yml
0 → 100644
View file @
5ede567d
---
title
:
Extend RBAC by having a service account restricted to project's namespace
merge_request
:
22011
author
:
type
:
other
This diff is collapsed.
Click to expand it.
lib/gitlab/kubernetes/role_binding.rb
View file @
5ede567d
...
...
@@ -3,9 +3,8 @@
module
Gitlab
module
Kubernetes
class
RoleBinding
attr_reader
:role_name
,
:namespace
,
:service_account_name
def
initialize
(
role_name
:,
namespace
:,
service_account_name
:)
def
initialize
(
name
:,
role_name
:,
namespace
:,
service_account_name
:)
@name
=
name
@role_name
=
role_name
@namespace
=
namespace
@service_account_name
=
service_account_name
...
...
@@ -21,14 +20,16 @@ module Gitlab
private
attr_reader
:name
,
:role_name
,
:namespace
,
:service_account_name
def
metadata
{
name:
"gitlab-
#{
namespace
}
"
,
namespace:
namespace
}
{
name:
name
,
namespace:
namespace
}
end
def
role_ref
{
apiGroup:
'rbac.authorization.k8s.io'
,
kind:
'Role'
,
kind:
'
Cluster
Role'
,
name:
role_name
}
end
...
...
This diff is collapsed.
Click to expand it.
spec/controllers/projects/clusters_controller_spec.rb
View file @
5ede567d
...
...
@@ -5,6 +5,7 @@ require 'spec_helper'
describe
Projects
::
ClustersController
do
include
AccessMatchersForController
include
GoogleApi
::
CloudPlatformHelpers
include
KubernetesHelpers
set
(
:project
)
{
create
(
:project
)
}
...
...
@@ -309,6 +310,11 @@ describe Projects::ClustersController do
end
describe
'security'
do
before
do
allow
(
ClusterPlatformConfigureWorker
).
to
receive
(
:perform_async
)
stub_kubeclient_get_namespace
(
'https://kubernetes.example.com'
,
namespace:
'my-namespace'
)
end
it
{
expect
{
go
}.
to
be_allowed_for
(
:admin
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:owner
).
of
(
project
)
}
it
{
expect
{
go
}.
to
be_allowed_for
(
:maintainer
).
of
(
project
)
}
...
...
@@ -412,6 +418,11 @@ describe Projects::ClustersController do
)
end
before
do
allow
(
ClusterPlatformConfigureWorker
).
to
receive
(
:perform_async
)
stub_kubeclient_get_namespace
(
'https://kubernetes.example.com'
,
namespace:
'my-namespace'
)
end
context
'when cluster is provided by GCP'
do
it
"updates and redirects back to show page"
do
go
...
...
This diff is collapsed.
Click to expand it.
spec/factories/clusters/kubernetes_namespaces.rb
View file @
5ede567d
...
...
@@ -2,8 +2,18 @@
FactoryBot
.
define
do
factory
:cluster_kubernetes_namespace
,
class:
Clusters
::
KubernetesNamespace
do
cluster
project
cluster_project
association
:cluster
,
:project
,
:provided_by_gcp
namespace
{
|
n
|
"environment
#{
n
}
"
}
after
(
:build
)
do
|
kubernetes_namespace
|
cluster_project
=
kubernetes_namespace
.
cluster
.
cluster_project
kubernetes_namespace
.
project
=
cluster_project
.
project
kubernetes_namespace
.
cluster_project
=
cluster_project
end
trait
:with_token
do
service_account_token
{
Faker
::
Lorem
.
characters
(
10
)
}
end
end
end
This diff is collapsed.
Click to expand it.
spec/features/projects/clusters/gcp_spec.rb
View file @
5ede567d
...
...
@@ -130,6 +130,7 @@ describe 'Gcp Cluster', :js do
context
'when user changes cluster parameters'
do
before
do
allow
(
ClusterPlatformConfigureWorker
).
to
receive
(
:perform_async
)
fill_in
'cluster_platform_kubernetes_attributes_namespace'
,
with:
'my-namespace'
page
.
within
(
'#js-cluster-details'
)
{
click_button
'Save changes'
}
end
...
...
This diff is collapsed.
Click to expand it.
spec/features/projects/clusters/user_spec.rb
View file @
5ede567d
...
...
@@ -9,7 +9,9 @@ describe 'User Cluster', :js do
before
do
project
.
add_maintainer
(
user
)
gitlab_sign_in
(
user
)
allow
(
Projects
::
ClustersController
).
to
receive
(
:STATUS_POLLING_INTERVAL
)
{
100
}
allow_any_instance_of
(
Clusters
::
Gcp
::
Kubernetes
::
CreateOrUpdateNamespaceService
).
to
receive
(
:execute
)
end
context
'when user does not have a cluster and visits cluster index page'
do
...
...
This diff is collapsed.
Click to expand it.
spec/lib/gitlab/kubernetes/role_binding_spec.rb
View file @
5ede567d
...
...
@@ -20,7 +20,7 @@ describe Gitlab::Kubernetes::RoleBinding, '#generate' do
let
(
:role_ref
)
do
{
apiGroup:
'rbac.authorization.k8s.io'
,
kind:
'Role'
,
kind:
'
Cluster
Role'
,
name:
role_name
}
end
...
...
@@ -35,6 +35,7 @@ describe Gitlab::Kubernetes::RoleBinding, '#generate' do
subject
do
described_class
.
new
(
name:
"gitlab-
#{
namespace
}
"
,
role_name:
role_name
,
namespace:
namespace
,
service_account_name:
service_account_name
...
...
This diff is collapsed.
Click to expand it.
spec/models/clusters/applications/prometheus_spec.rb
View file @
5ede567d
...
...
@@ -109,14 +109,20 @@ describe Clusters::Applications::Prometheus do
end
context
'cluster has kubeclient'
do
let
(
:cluster
)
{
create
(
:cluster
,
:project
,
:provided_by_gcp
)
}
let
(
:kubernetes_url
)
{
subject
.
cluster
.
platform_kubernetes
.
api_url
}
let
(
:kube_client
)
{
subject
.
cluster
.
kubeclient
.
core_client
}
subject
{
create
(
:clusters_applications_prometheus
)
}
subject
{
create
(
:clusters_applications_prometheus
,
cluster:
cluster
)
}
before
do
subject
.
cluster
.
platform_kubernetes
.
namespace
=
'a-namespace'
stub_kubeclient_discover
(
subject
.
cluster
.
platform_kubernetes
.
api_url
)
stub_kubeclient_discover
(
cluster
.
platform_kubernetes
.
api_url
)
create
(
:cluster_kubernetes_namespace
,
cluster:
cluster
,
cluster_project:
cluster
.
cluster_project
,
project:
cluster
.
cluster_project
.
project
)
end
it
'creates proxy prometheus rest client'
do
...
...
This diff is collapsed.
Click to expand it.
spec/models/clusters/cluster_spec.rb
View file @
5ede567d
...
...
@@ -16,6 +16,7 @@ describe Clusters::Cluster do
it
{
is_expected
.
to
have_one
(
:application_runner
)
}
it
{
is_expected
.
to
have_many
(
:kubernetes_namespaces
)
}
it
{
is_expected
.
to
have_one
(
:kubernetes_namespace
)
}
it
{
is_expected
.
to
have_one
(
:cluster_project
)
}
it
{
is_expected
.
to
delegate_method
(
:status
).
to
(
:provider
)
}
it
{
is_expected
.
to
delegate_method
(
:status_reason
).
to
(
:provider
)
}
...
...
This diff is collapsed.
Click to expand it.
spec/models/clusters/kubernetes_namespace_spec.rb
View file @
5ede567d
...
...
@@ -10,23 +10,15 @@ RSpec.describe Clusters::KubernetesNamespace, type: :model do
describe
'namespace uniqueness validation'
do
let
(
:cluster_project
)
{
create
(
:cluster_project
)
}
let
(
:kubernetes_namespace
)
do
build
(
:cluster_kubernetes_namespace
,
cluster:
cluster_project
.
cluster
,
project:
cluster_project
.
project
,
cluster_project:
cluster_project
)
end
let
(
:kubernetes_namespace
)
{
build
(
:cluster_kubernetes_namespace
,
namespace:
'my-namespace'
)
}
subject
{
kubernetes_namespace
}
context
'when cluster is using the namespace'
do
before
do
create
(
:cluster_kubernetes_namespace
,
cluster:
cluster_project
.
cluster
,
project:
cluster_project
.
project
,
cluster_project:
cluster_project
,
namespace:
kubernetes_namespace
.
namespace
)
cluster:
kubernetes_namespace
.
cluster
,
namespace:
'my-namespace'
)
end
it
{
is_expected
.
not_to
be_valid
}
...
...
@@ -37,48 +29,79 @@ RSpec.describe Clusters::KubernetesNamespace, type: :model do
end
end
describe
'#set_namespace_and_service_account_to_default'
do
let
(
:cluster
)
{
platform
.
cluster
}
let
(
:cluster_project
)
{
create
(
:cluster_project
,
cluster:
cluster
)
}
let
(
:kubernetes_namespace
)
do
create
(
:cluster_kubernetes_namespace
,
cluster:
cluster_project
.
cluster
,
project:
cluster_project
.
project
,
cluster_project:
cluster_project
)
end
describe
'#configure_predefined_variables'
do
let
(
:kubernetes_namespace
)
{
build
(
:cluster_kubernetes_namespace
)
}
let
(
:cluster
)
{
kubernetes_namespace
.
cluster
}
let
(
:platform
)
{
kubernetes_namespace
.
platform_kubernetes
}
describe
'namespace'
do
let
(
:platform
)
{
create
(
:cluster_platform_kubernetes
,
namespace:
namespace
)
}
subject
{
kubernetes_namespace
.
configure_predefined_credentials
}
subject
{
kubernetes_namespace
.
namespace
}
describe
'namespace'
do
before
do
platform
.
update_column
(
:namespace
,
namespace
)
end
context
'when platform has a namespace assigned'
do
let
(
:namespace
)
{
'platform-namespace'
}
it
'should copy the namespace'
do
is_expected
.
to
eq
(
'platform-namespace'
)
subject
expect
(
kubernetes_namespace
.
namespace
).
to
eq
(
'platform-namespace'
)
end
end
context
'when platform does not have namespace assigned'
do
let
(
:project
)
{
kubernetes_namespace
.
project
}
let
(
:namespace
)
{
nil
}
let
(
:project_slug
)
{
"
#{
project
.
path
}
-
#{
project
.
id
}
"
}
it
'should
set defaul
t namespace'
do
project_slug
=
"
#{
cluster_project
.
project
.
path
}
-
#{
cluster_project
.
project_id
}
"
it
'should
fallback to projec
t namespace'
do
subject
is_expected
.
to
eq
(
project_slug
)
expect
(
kubernetes_namespace
.
namespace
)
.
to
eq
(
project_slug
)
end
end
end
describe
'service_account_name'
do
let
(
:platform
)
{
create
(
:cluster_platform_kubernetes
)
}
subject
{
kubernetes_namespace
.
service_account_name
}
let
(
:service_account_name
)
{
"
#{
kubernetes_namespace
.
namespace
}
-service-account"
}
it
'should set a service account name based on namespace'
do
is_expected
.
to
eq
(
"
#{
kubernetes_namespace
.
namespace
}
-service-account"
)
subject
expect
(
kubernetes_namespace
.
service_account_name
).
to
eq
(
service_account_name
)
end
end
end
describe
'#predefined_variables'
do
let
(
:kubernetes_namespace
)
{
create
(
:cluster_kubernetes_namespace
,
cluster:
cluster
,
service_account_token:
token
)
}
let
(
:cluster
)
{
create
(
:cluster
,
:project
,
platform_kubernetes:
platform
)
}
let
(
:platform
)
{
create
(
:cluster_platform_kubernetes
,
api_url:
api_url
,
ca_cert:
ca_pem
,
token:
token
)
}
let
(
:api_url
)
{
'https://kube.domain.com'
}
let
(
:ca_pem
)
{
'CA PEM DATA'
}
let
(
:token
)
{
'token'
}
let
(
:kubeconfig
)
do
config_file
=
expand_fixture_path
(
'config/kubeconfig.yml'
)
config
=
YAML
.
safe_load
(
File
.
read
(
config_file
))
config
.
dig
(
'users'
,
0
,
'user'
)[
'token'
]
=
token
config
.
dig
(
'contexts'
,
0
,
'context'
)[
'namespace'
]
=
kubernetes_namespace
.
namespace
config
.
dig
(
'clusters'
,
0
,
'cluster'
)[
'certificate-authority-data'
]
=
Base64
.
strict_encode64
(
ca_pem
)
YAML
.
dump
(
config
)
end
it
'sets the variables'
do
expect
(
kubernetes_namespace
.
predefined_variables
).
to
include
(
{
key:
'KUBE_SERVICE_ACCOUNT'
,
value:
kubernetes_namespace
.
service_account_name
,
public:
true
},
{
key:
'KUBE_NAMESPACE'
,
value:
kubernetes_namespace
.
namespace
,
public:
true
},
{
key:
'KUBE_TOKEN'
,
value:
kubernetes_namespace
.
service_account_token
,
public:
false
},
{
key:
'KUBECONFIG'
,
value:
kubeconfig
,
public:
false
,
file:
true
}
)
end
end
end
This diff is collapsed.
Click to expand it.
spec/models/clusters/platforms/kubernetes_spec.rb
View file @
5ede567d
...
...
@@ -124,9 +124,17 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
end
describe
'#kubeclient'
do
let
(
:cluster
)
{
create
(
:cluster
,
:project
)
}
let
(
:kubernetes
)
{
build
(
:cluster_platform_kubernetes
,
:configured
,
namespace:
'a-namespace'
,
cluster:
cluster
)
}
subject
{
kubernetes
.
kubeclient
}
let
(
:kubernetes
)
{
build
(
:cluster_platform_kubernetes
,
:configured
,
namespace:
'a-namespace'
)
}
before
do
create
(
:cluster_kubernetes_namespace
,
cluster:
kubernetes
.
cluster
,
cluster_project:
kubernetes
.
cluster
.
cluster_project
,
project:
kubernetes
.
cluster
.
cluster_project
.
project
)
end
it
{
is_expected
.
to
be_an_instance_of
(
Gitlab
::
Kubernetes
::
KubeClient
)
}
end
...
...
@@ -186,29 +194,14 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
describe
'#predefined_variables'
do
let!
(
:cluster
)
{
create
(
:cluster
,
:project
,
platform_kubernetes:
kubernetes
)
}
let
(
:kubernetes
)
{
create
(
:cluster_platform_kubernetes
,
api_url:
api_url
,
ca_cert:
ca_pem
,
token:
token
)
}
let
(
:kubernetes
)
{
create
(
:cluster_platform_kubernetes
,
api_url:
api_url
,
ca_cert:
ca_pem
)
}
let
(
:api_url
)
{
'https://kube.domain.com'
}
let
(
:ca_pem
)
{
'CA PEM DATA'
}
let
(
:token
)
{
'token'
}
let
(
:kubeconfig
)
do
config_file
=
expand_fixture_path
(
'config/kubeconfig.yml'
)
config
=
YAML
.
load
(
File
.
read
(
config_file
))
config
.
dig
(
'users'
,
0
,
'user'
)[
'token'
]
=
token
config
.
dig
(
'contexts'
,
0
,
'context'
)[
'namespace'
]
=
namespace
config
.
dig
(
'clusters'
,
0
,
'cluster'
)[
'certificate-authority-data'
]
=
Base64
.
strict_encode64
(
ca_pem
)
YAML
.
dump
(
config
)
end
shared_examples
'setting variables'
do
it
'sets the variables'
do
expect
(
kubernetes
.
predefined_variables
).
to
include
(
expect
(
kubernetes
.
predefined_variables
(
project:
cluster
.
project
)
).
to
include
(
{
key:
'KUBE_URL'
,
value:
api_url
,
public:
true
},
{
key:
'KUBE_TOKEN'
,
value:
token
,
public:
false
},
{
key:
'KUBE_NAMESPACE'
,
value:
namespace
,
public:
true
},
{
key:
'KUBECONFIG'
,
value:
kubeconfig
,
public:
false
,
file:
true
},
{
key:
'KUBE_CA_PEM'
,
value:
ca_pem
,
public:
true
},
{
key:
'KUBE_CA_PEM_FILE'
,
value:
ca_pem
,
public:
true
,
file:
true
}
)
...
...
@@ -229,13 +222,6 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
let
(
:namespace
)
{
kubernetes
.
actual_namespace
}
it_behaves_like
'setting variables'
it
'sets the KUBE_NAMESPACE'
do
kube_namespace
=
kubernetes
.
predefined_variables
.
find
{
|
h
|
h
[
:key
]
==
'KUBE_NAMESPACE'
}
expect
(
kube_namespace
).
not_to
be_nil
expect
(
kube_namespace
[
:value
]).
to
match
(
/\A
#{
Gitlab
::
PathRegex
::
PATH_REGEX_STR
}
-\d+\z/
)
end
end
end
...
...
@@ -319,4 +305,27 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
it
{
is_expected
.
to
include
(
pods:
[])
}
end
end
describe
'#update_kubernetes_namespace'
do
let
(
:cluster
)
{
create
(
:cluster
,
:provided_by_gcp
)
}
let
(
:platform
)
{
cluster
.
platform
}
context
'when namespace is updated'
do
it
'should call ConfigureWorker'
do
expect
(
ClusterPlatformConfigureWorker
).
to
receive
(
:perform_async
).
with
(
cluster
.
id
).
once
platform
.
namespace
=
'new-namespace'
platform
.
save
end
end
context
'when namespace is not updated'
do
it
'should not call ConfigureWorker'
do
expect
(
ClusterPlatformConfigureWorker
).
not_to
receive
(
:perform_async
)
platform
.
username
=
"new-username"
platform
.
save
end
end
end
end
This diff is collapsed.
Click to expand it.
spec/models/project_services/kubernetes_service_spec.rb
View file @
5ede567d
...
...
@@ -253,7 +253,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
end
end
describe
'#predefined_variable
s
'
do
describe
'#predefined_variable'
do
let
(
:kubeconfig
)
do
config_file
=
expand_fixture_path
(
'config/kubeconfig.yml'
)
config
=
YAML
.
load
(
File
.
read
(
config_file
))
...
...
@@ -274,7 +274,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
shared_examples
'setting variables'
do
it
'sets the variables'
do
expect
(
subject
.
predefined_variables
).
to
include
(
expect
(
subject
.
predefined_variables
(
project:
project
)
).
to
include
(
{
key:
'KUBE_URL'
,
value:
'https://kube.domain.com'
,
public:
true
},
{
key:
'KUBE_TOKEN'
,
value:
'token'
,
public:
false
},
{
key:
'KUBE_NAMESPACE'
,
value:
namespace
,
public:
true
},
...
...
@@ -301,7 +301,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
it_behaves_like
'setting variables'
it
'sets the KUBE_NAMESPACE'
do
kube_namespace
=
subject
.
predefined_variables
.
find
{
|
h
|
h
[
:key
]
==
'KUBE_NAMESPACE'
}
kube_namespace
=
subject
.
predefined_variables
(
project:
project
)
.
find
{
|
h
|
h
[
:key
]
==
'KUBE_NAMESPACE'
}
expect
(
kube_namespace
).
not_to
be_nil
expect
(
kube_namespace
[
:value
]).
to
match
(
/\A
#{
Gitlab
::
PathRegex
::
PATH_REGEX_STR
}
-\d+\z/
)
...
...
This diff is collapsed.
Click to expand it.
spec/models/project_spec.rb
View file @
5ede567d
...
...
@@ -2405,12 +2405,24 @@ describe Project do
it_behaves_like
'same behavior between KubernetesService and Platform::Kubernetes'
end
context
'when user configured kubernetes from CI/CD > Clusters'
do
context
'when user configured kubernetes from CI/CD > Clusters
and KubernetesNamespace migration has not been executed
'
do
let!
(
:cluster
)
{
create
(
:cluster
,
:project
,
:provided_by_gcp
)
}
let
(
:project
)
{
cluster
.
project
}
it_behaves_like
'same behavior between KubernetesService and Platform::Kubernetes'
end
context
'when user configured kubernetes from CI/CD > Clusters and KubernetesNamespace migration has been executed'
do
let!
(
:kubernetes_namespace
)
{
create
(
:cluster_kubernetes_namespace
)
}
let!
(
:cluster
)
{
kubernetes_namespace
.
cluster
}
let
(
:project
)
{
kubernetes_namespace
.
project
}
it
'should return token from kubernetes namespace'
do
expect
(
project
.
deployment_variables
).
to
include
(
{
key:
'KUBE_TOKEN'
,
value:
kubernetes_namespace
.
service_account_token
,
public:
false
}
)
end
end
end
end
...
...
This diff is collapsed.
Click to expand it.
spec/services/clusters/gcp/finalize_creation_service_spec.rb
View file @
5ede567d
# frozen_string_literal: true
require
'spec_helper'
describe
Clusters
::
Gcp
::
FinalizeCreationService
do
describe
Clusters
::
Gcp
::
FinalizeCreationService
,
'#execute'
do
include
GoogleApi
::
CloudPlatformHelpers
include
KubernetesHelpers
describe
'#execute'
do
let
(
:cluster
)
{
create
(
:cluster
,
:project
,
:providing_by_gcp
)
}
let
(
:provider
)
{
cluster
.
provider
}
let
(
:platform
)
{
cluster
.
platform
}
let
(
:gcp_project_id
)
{
provider
.
gcp_project_id
}
let
(
:zone
)
{
provider
.
zone
}
let
(
:cluster_name
)
{
cluster
.
name
}
let
(
:cluster
)
{
create
(
:cluster
,
:project
,
:providing_by_gcp
)
}
let
(
:provider
)
{
cluster
.
provider
}
let
(
:platform
)
{
cluster
.
platform
}
let
(
:endpoint
)
{
'111.111.111.111'
}
let
(
:api_url
)
{
'https://'
+
endpoint
}
let
(
:username
)
{
'sample-username'
}
let
(
:password
)
{
'sample-password'
}
let
(
:secret_name
)
{
'gitlab-token'
}
let
(
:token
)
{
'sample-token'
}
let
(
:namespace
)
{
"
#{
cluster
.
project
.
path
}
-
#{
cluster
.
project
.
id
}
"
}
subject
{
described_class
.
new
.
execute
(
provider
)
}
subject
{
described_class
.
new
.
execute
(
provider
)
}
shared_examples
'success'
do
it
'configures provider and kubernetes'
do
subject
shared_examples
'success'
do
it
'configures provider and kubernetes'
do
subject
expect
(
provider
).
to
be_created
end
expect
(
provider
).
to
be_created
end
shared_examples
'error'
do
it
'sets an error to provider object'
do
subject
it
'properly configures database models'
do
subject
expect
(
provider
.
reload
).
to
be_errored
end
cluster
.
reload
expect
(
provider
.
endpoint
).
to
eq
(
endpoint
)
expect
(
platform
.
api_url
).
to
eq
(
api_url
)
expect
(
platform
.
ca_cert
).
to
eq
(
Base64
.
decode64
(
load_sample_cert
))
expect
(
platform
.
username
).
to
eq
(
username
)
expect
(
platform
.
password
).
to
eq
(
password
)
expect
(
platform
.
token
).
to
eq
(
token
)
end
it
'creates kubernetes namespace model'
do
subject
kubernetes_namespace
=
cluster
.
reload
.
kubernetes_namespace
expect
(
kubernetes_namespace
).
to
be_persisted
expect
(
kubernetes_namespace
.
namespace
).
to
eq
(
namespace
)
expect
(
kubernetes_namespace
.
service_account_name
).
to
eq
(
"
#{
namespace
}
-service-account"
)
expect
(
kubernetes_namespace
.
service_account_token
).
to
be_present
end
end
shared_examples
'error'
do
it
'sets an error to provider object'
do
subject
context
'when succeeded to fetch gke cluster info'
do
let
(
:endpoint
)
{
'111.111.111.111'
}
let
(
:api_url
)
{
'https://'
+
endpoint
}
let
(
:username
)
{
'sample-username'
}
let
(
:password
)
{
'sample-password'
}
let
(
:secret_name
)
{
'gitlab-token'
}
expect
(
provider
.
reload
).
to
be_errored
end
end
shared_examples
'kubernetes information not successfully fetched'
do
context
'when failed to fetch gke cluster info'
do
before
do
stub_cloud_platform_get_zone_cluster
(
gcp_project_id
,
zone
,
cluster_name
,
{
endpoint:
endpoint
,
username:
username
,
password:
password
}
)
stub_cloud_platform_get_zone_cluster_error
(
provider
.
gcp_project_id
,
provider
.
zone
,
cluster
.
name
)
end
context
'service account and token created'
do
before
do
stub_kubeclient_discover
(
api_url
)
stub_kubeclient_create_service_account
(
api_url
)
stub_kubeclient_create_secret
(
api_url
)
end
shared_context
'kubernetes token successfully fetched'
do
let
(
:token
)
{
'sample-token'
}
before
do
stub_kubeclient_get_secret
(
api_url
,
{
metadata_name:
secret_name
,
token:
Base64
.
encode64
(
token
)
}
)
end
end
context
'provider legacy_abac is enabled'
do
include_context
'kubernetes token successfully fetched'
it_behaves_like
'success'
it
'properly configures database models'
do
subject
cluster
.
reload
expect
(
provider
.
endpoint
).
to
eq
(
endpoint
)
expect
(
platform
.
api_url
).
to
eq
(
api_url
)
expect
(
platform
.
ca_cert
).
to
eq
(
Base64
.
decode64
(
load_sample_cert
))
expect
(
platform
.
username
).
to
eq
(
username
)
expect
(
platform
.
password
).
to
eq
(
password
)
expect
(
platform
).
to
be_abac
expect
(
platform
.
authorization_type
).
to
eq
(
'abac'
)
expect
(
platform
.
token
).
to
eq
(
token
)
end
end
context
'provider legacy_abac is disabled'
do
before
do
provider
.
legacy_abac
=
false
end
include_context
'kubernetes token successfully fetched'
context
'cluster role binding created'
do
before
do
stub_kubeclient_create_cluster_role_binding
(
api_url
)
end
it_behaves_like
'success'
it
'properly configures database models'
do
subject
cluster
.
reload
expect
(
provider
.
endpoint
).
to
eq
(
endpoint
)
expect
(
platform
.
api_url
).
to
eq
(
api_url
)
expect
(
platform
.
ca_cert
).
to
eq
(
Base64
.
decode64
(
load_sample_cert
))
expect
(
platform
.
username
).
to
eq
(
username
)
expect
(
platform
.
password
).
to
eq
(
password
)
expect
(
platform
).
to
be_rbac
expect
(
platform
.
token
).
to
eq
(
token
)
end
end
end
context
'when token is empty'
do
before
do
stub_kubeclient_get_secret
(
api_url
,
token:
''
,
metadata_name:
secret_name
)
end
it_behaves_like
'error'
end
context
'when failed to fetch kubernetes token'
do
before
do
stub_kubeclient_get_secret_error
(
api_url
,
secret_name
)
end
it_behaves_like
'error'
end
context
'when service account fails to create'
do
before
do
stub_kubeclient_create_service_account_error
(
api_url
)
end
it_behaves_like
'error'
end
it_behaves_like
'error'
end
context
'when token is empty'
do
let
(
:token
)
{
''
}
it_behaves_like
'error'
end
context
'when failed to fetch kubernetes token'
do
before
do
stub_kubeclient_get_secret_error
(
api_url
,
secret_name
,
namespace:
'default'
)
end
it_behaves_like
'error'
end
context
'when
failed to fetch gke cluster info
'
do
context
'when
service account fails to create
'
do
before
do
stub_
cloud_platform_get_zone_cluster_error
(
gcp_project_id
,
zone
,
cluster_name
)
stub_
kubeclient_create_service_account_error
(
api_url
,
namespace:
'default'
)
end
it_behaves_like
'error'
end
end
shared_context
'kubernetes information successfully fetched'
do
before
do
stub_cloud_platform_get_zone_cluster
(
provider
.
gcp_project_id
,
provider
.
zone
,
cluster
.
name
,
{
endpoint:
endpoint
,
username:
username
,
password:
password
}
)
stub_kubeclient_discover
(
api_url
)
stub_kubeclient_get_namespace
(
api_url
)
stub_kubeclient_create_namespace
(
api_url
)
stub_kubeclient_create_service_account
(
api_url
)
stub_kubeclient_create_secret
(
api_url
)
stub_kubeclient_get_secret
(
api_url
,
{
metadata_name:
secret_name
,
token:
Base64
.
encode64
(
token
),
namespace:
'default'
}
)
stub_kubeclient_get_namespace
(
api_url
,
namespace:
namespace
)
stub_kubeclient_create_service_account
(
api_url
,
namespace:
namespace
)
stub_kubeclient_create_secret
(
api_url
,
namespace:
namespace
)
stub_kubeclient_get_secret
(
api_url
,
{
metadata_name:
"
#{
namespace
}
-token"
,
token:
Base64
.
encode64
(
token
),
namespace:
namespace
}
)
end
end
context
'With a legacy ABAC cluster'
do
before
do
provider
.
legacy_abac
=
true
end
include_context
'kubernetes information successfully fetched'
it_behaves_like
'success'
it
'uses ABAC authorization type'
do
subject
cluster
.
reload
expect
(
platform
).
to
be_abac
expect
(
platform
.
authorization_type
).
to
eq
(
'abac'
)
end
it_behaves_like
'kubernetes information not successfully fetched'
end
context
'With an RBAC cluster'
do
before
do
provider
.
legacy_abac
=
false
stub_kubeclient_create_cluster_role_binding
(
api_url
)
stub_kubeclient_create_role_binding
(
api_url
,
namespace:
namespace
)
end
include_context
'kubernetes information successfully fetched'
it_behaves_like
'success'
it
'uses RBAC authorization type'
do
subject
cluster
.
reload
expect
(
platform
).
to
be_rbac
expect
(
platform
.
authorization_type
).
to
eq
(
'rbac'
)
end
it_behaves_like
'kubernetes information not successfully fetched'
end
end
This diff is collapsed.
Click to expand it.
spec/services/clusters/gcp/kubernetes/create_or_update_namespace_service_spec.rb
0 → 100644
View file @
5ede567d
# frozen_string_literal: true
require
'spec_helper'
describe
Clusters
::
Gcp
::
Kubernetes
::
CreateOrUpdateNamespaceService
,
'#execute'
do
include
KubernetesHelpers
let
(
:cluster
)
{
create
(
:cluster
,
:project
,
:provided_by_gcp
)
}
let
(
:platform
)
{
cluster
.
platform
}
let
(
:api_url
)
{
'https://kubernetes.example.com'
}
let
(
:project
)
{
cluster
.
project
}
let
(
:cluster_project
)
{
cluster
.
cluster_project
}
subject
do
described_class
.
new
(
cluster:
cluster
,
kubernetes_namespace:
kubernetes_namespace
).
execute
end
shared_context
'kubernetes requests'
do
before
do
stub_kubeclient_discover
(
api_url
)
stub_kubeclient_get_namespace
(
api_url
)
stub_kubeclient_create_service_account
(
api_url
)
stub_kubeclient_create_secret
(
api_url
)
stub_kubeclient_get_namespace
(
api_url
,
namespace:
namespace
)
stub_kubeclient_create_service_account
(
api_url
,
namespace:
namespace
)
stub_kubeclient_create_secret
(
api_url
,
namespace:
namespace
)
stub_kubeclient_get_secret
(
api_url
,
{
metadata_name:
"
#{
namespace
}
-token"
,
token:
Base64
.
encode64
(
'sample-token'
),
namespace:
namespace
}
)
end
end
context
'when kubernetes namespace is not persisted'
do
let
(
:namespace
)
{
"
#{
project
.
path
}
-
#{
project
.
id
}
"
}
let
(
:kubernetes_namespace
)
do
build
(
:cluster_kubernetes_namespace
,
cluster:
cluster
,
project:
cluster_project
.
project
,
cluster_project:
cluster_project
)
end
include_context
'kubernetes requests'
it
'creates a Clusters::KubernetesNamespace'
do
expect
do
subject
end
.
to
change
(
Clusters
::
KubernetesNamespace
,
:count
).
by
(
1
)
end
it
'creates project service account'
do
expect_any_instance_of
(
Clusters
::
Gcp
::
Kubernetes
::
CreateServiceAccountService
).
to
receive
(
:execute
).
once
subject
end
it
'configures kubernetes token'
do
subject
kubernetes_namespace
.
reload
expect
(
kubernetes_namespace
.
namespace
).
to
eq
(
namespace
)
expect
(
kubernetes_namespace
.
service_account_name
).
to
eq
(
"
#{
namespace
}
-service-account"
)
expect
(
kubernetes_namespace
.
encrypted_service_account_token
).
to
be_present
end
end
context
'when there is a Kubernetes Namespace associated'
do
let
(
:namespace
)
{
'new-namespace'
}
let
(
:kubernetes_namespace
)
do
create
(
:cluster_kubernetes_namespace
,
cluster:
cluster
,
project:
cluster_project
.
project
,
cluster_project:
cluster_project
)
end
include_context
'kubernetes requests'
before
do
platform
.
update_column
(
:namespace
,
'new-namespace'
)
end
it
'does not create any Clusters::KubernetesNamespace'
do
subject
expect
(
cluster
.
kubernetes_namespace
).
to
eq
(
kubernetes_namespace
)
end
it
'creates project service account'
do
expect_any_instance_of
(
Clusters
::
Gcp
::
Kubernetes
::
CreateServiceAccountService
).
to
receive
(
:execute
).
once
subject
end
it
'updates Clusters::KubernetesNamespace'
do
subject
kubernetes_namespace
.
reload
expect
(
kubernetes_namespace
.
namespace
).
to
eq
(
namespace
)
expect
(
kubernetes_namespace
.
service_account_name
).
to
eq
(
"
#{
namespace
}
-service-account"
)
expect
(
kubernetes_namespace
.
encrypted_service_account_token
).
to
be_present
end
end
end
This diff is collapsed.
Click to expand it.
spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb
View file @
5ede567d
# frozen_string_literal: true
require
'spec_helper'
describe
Clusters
::
Gcp
::
Kubernetes
::
CreateServiceAccountService
do
include
KubernetesHelpers
let
(
:service
)
{
described_class
.
new
(
kubeclient
,
rbac:
rbac
)
}
let
(
:api_url
)
{
'http://111.111.111.111'
}
let
(
:platform_kubernetes
)
{
cluster
.
platform_kubernetes
}
let
(
:cluster_project
)
{
cluster
.
cluster_project
}
let
(
:project
)
{
cluster_project
.
project
}
let
(
:cluster
)
do
create
(
:cluster
,
:project
,
:provided_by_gcp
,
platform_kubernetes:
create
(
:cluster_platform_kubernetes
,
:configured
))
end
let
(
:kubeclient
)
do
Gitlab
::
Kubernetes
::
KubeClient
.
new
(
api_url
,
auth_options:
{
username:
'admin'
,
password:
'xxx'
}
)
end
describe
'#execute'
do
let
(
:rbac
)
{
false
}
let
(
:api_url
)
{
'http://111.111.111.111'
}
let
(
:username
)
{
'admin'
}
let
(
:password
)
{
'xxx'
}
shared_examples
'creates service account and token'
do
it
'creates a kubernetes service account'
do
subject
expect
(
WebMock
).
to
have_requested
(
:post
,
api_url
+
"/api/v1/namespaces/
#{
namespace
}
/serviceaccounts"
).
with
(
body:
hash_including
(
kind:
'ServiceAccount'
,
metadata:
{
name:
service_account_name
,
namespace:
namespace
}
)
)
end
let
(
:kubeclient
)
do
Gitlab
::
Kubernetes
::
KubeClient
.
new
(
api_url
,
auth_options:
{
username:
username
,
password:
password
}
it
'creates a kubernetes secret'
do
subject
expect
(
WebMock
).
to
have_requested
(
:post
,
api_url
+
"/api/v1/namespaces/
#{
namespace
}
/secrets"
).
with
(
body:
hash_including
(
kind:
'Secret'
,
metadata:
{
name:
token_name
,
namespace:
namespace
,
annotations:
{
'kubernetes.io/service-account.name'
:
service_account_name
}
},
type:
'kubernetes.io/service-account-token'
)
)
end
end
before
do
stub_kubeclient_discover
(
api_url
)
stub_kubeclient_get_namespace
(
api_url
,
namespace:
namespace
)
stub_kubeclient_create_service_account
(
api_url
,
namespace:
namespace
)
stub_kubeclient_create_secret
(
api_url
,
namespace:
namespace
)
end
describe
'.gitlab_creator'
do
let
(
:namespace
)
{
'default'
}
let
(
:service_account_name
)
{
'gitlab'
}
let
(
:token_name
)
{
'gitlab-token'
}
subject
{
described_class
.
gitlab_creator
(
kubeclient
,
rbac:
rbac
).
execute
}
context
'with ABAC cluster'
do
let
(
:rbac
)
{
false
}
it_behaves_like
'creates service account and token'
end
subject
{
service
.
execute
}
context
'with RBAC cluster'
do
let
(
:rbac
)
{
true
}
context
'when params are correct'
do
before
do
stub_kubeclient_discover
(
api_url
)
stub_kubeclient_create_service_account
(
api_url
)
stub_kubeclient_create_secret
(
api_url
)
end
cluster
.
platform_kubernetes
.
rbac!
shared_examples
'creates service account and token'
do
it
'creates a kubernetes service account'
do
subject
stub_kubeclient_create_cluster_role_binding
(
api_url
)
end
expect
(
WebMock
).
to
have_requested
(
:post
,
api_url
+
'/api/v1/namespaces/default/serviceaccounts'
).
with
(
body:
hash_including
(
kind:
'ServiceAccount'
,
metadata:
{
name:
'gitlab'
,
namespace:
'default'
}
)
)
end
it
'creates a kubernetes secret of type ServiceAccountToken'
do
subject
expect
(
WebMock
).
to
have_requested
(
:post
,
api_url
+
'/api/v1/namespaces/default/secrets'
).
with
(
body:
hash_including
(
kind:
'Secret'
,
metadata:
{
name:
'gitlab-token'
,
namespace:
'default'
,
annotations:
{
'kubernetes.io/service-account.name'
:
'gitlab'
}
},
type:
'kubernetes.io/service-account-token'
)
it_behaves_like
'creates service account and token'
it
'should create a cluster role binding with cluster-admin access'
do
subject
expect
(
WebMock
).
to
have_requested
(
:post
,
api_url
+
"/apis/rbac.authorization.k8s.io/v1/clusterrolebindings"
).
with
(
body:
hash_including
(
kind:
'ClusterRoleBinding'
,
metadata:
{
name:
'gitlab-admin'
},
roleRef:
{
apiGroup:
'rbac.authorization.k8s.io'
,
kind:
'ClusterRole'
,
name:
'cluster-admin'
},
subjects:
[
{
kind:
'ServiceAccount'
,
name:
service_account_name
,
namespace:
namespace
}
]
)
end
)
end
end
end
describe
'.namespace_creator'
do
let
(
:namespace
)
{
"
#{
project
.
path
}
-
#{
project
.
id
}
"
}
let
(
:service_account_name
)
{
"
#{
namespace
}
-service-account"
}
let
(
:token_name
)
{
"
#{
namespace
}
-token"
}
subject
do
described_class
.
namespace_creator
(
kubeclient
,
service_account_name:
service_account_name
,
service_account_namespace:
namespace
,
rbac:
rbac
).
execute
end
context
'with ABAC cluster'
do
let
(
:rbac
)
{
false
}
it_behaves_like
'creates service account and token'
end
context
'With RBAC enabled cluster'
do
let
(
:rbac
)
{
true
}
before
do
cluster
.
platform_kubernetes
.
rbac!
context
'abac enabled cluster'
do
it_behaves_like
'creates service account and token'
stub_kubeclient_create_role_binding
(
api_url
,
namespace:
namespace
)
end
context
'rbac enabled cluster'
do
let
(
:rbac
)
{
true
}
before
do
stub_kubeclient_create_cluster_role_binding
(
api_url
)
end
it_behaves_like
'creates service account and token'
it
'creates a kubernetes cluster role binding'
do
subject
expect
(
WebMock
).
to
have_requested
(
:post
,
api_url
+
'/apis/rbac.authorization.k8s.io/v1/clusterrolebindings'
).
with
(
body:
hash_including
(
kind:
'ClusterRoleBinding'
,
metadata:
{
name:
'gitlab-admin'
},
roleRef:
{
apiGroup:
'rbac.authorization.k8s.io'
,
kind:
'ClusterRole'
,
name:
'cluster-admin'
},
subjects:
[{
kind:
'ServiceAccount'
,
namespace:
'default'
,
name:
'gitlab'
}]
)
it_behaves_like
'creates service account and token'
it
'creates a namespaced role binding with edit access'
do
subject
expect
(
WebMock
).
to
have_requested
(
:post
,
api_url
+
"/apis/rbac.authorization.k8s.io/v1/namespaces/
#{
namespace
}
/rolebindings"
).
with
(
body:
hash_including
(
kind:
'RoleBinding'
,
metadata:
{
name:
"gitlab-
#{
namespace
}
"
,
namespace:
"
#{
namespace
}
"
},
roleRef:
{
apiGroup:
'rbac.authorization.k8s.io'
,
kind:
'ClusterRole'
,
name:
'edit'
},
subjects:
[
{
kind:
'ServiceAccount'
,
name:
service_account_name
,
namespace:
namespace
}
]
)
end
)
end
end
end
...
...
This diff is collapsed.
Click to expand it.
spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb
View file @
5ede567d
# frozen_string_literal: true
require
'
fast_
spec_helper'
require
'spec_helper'
describe
Clusters
::
Gcp
::
Kubernetes
::
FetchKubernetesTokenService
do
include
KubernetesHelpers
describe
'#execute'
do
let
(
:api_url
)
{
'http://111.111.111.111'
}
let
(
:
username
)
{
'admin
'
}
let
(
:
password
)
{
'xxx
'
}
let
(
:
namespace
)
{
'my-namespace
'
}
let
(
:
service_account_token_name
)
{
'gitlab-token
'
}
let
(
:kubeclient
)
do
Gitlab
::
Kubernetes
::
KubeClient
.
new
(
api_url
,
auth_options:
{
username:
username
,
password:
password
}
auth_options:
{
username:
'admin'
,
password:
'xxx'
}
)
end
subject
{
described_class
.
new
(
kubeclient
).
execute
}
subject
{
described_class
.
new
(
kubeclient
,
service_account_token_name
,
namespace
).
execute
}
context
'when params correct'
do
let
(
:decoded_token
)
{
'xxx.token.xxx'
}
let
(
:token
)
{
Base64
.
encode64
(
decoded_token
)
}
let
(
:secret_json
)
do
{
'metadata'
:
{
name:
'gitlab-token'
},
'data'
:
{
'token'
:
token
}
}
end
before
do
allow_any_instance_of
(
Kubeclient
::
Client
)
.
to
receive
(
:get_secret
).
and_return
(
secret_json
)
end
context
'when gitlab-token exists'
do
let
(
:metadata_name
)
{
'gitlab-token'
}
before
do
stub_kubeclient_discover
(
api_url
)
stub_kubeclient_get_secret
(
api_url
,
{
metadata_name:
service_account_token_name
,
namespace:
namespace
,
token:
token
}
)
end
it
{
is_expected
.
to
eq
(
decoded_token
)
}
end
context
'when gitlab-token does not exist'
do
let
(
:secret_json
)
{
{}
}
it
{
is_expected
.
to
be_nil
}
end
context
'when token is nil'
do
let
(
:token
)
{
nil
}
before
do
allow
(
kubeclient
).
to
receive
(
:get_secret
).
and_raise
(
Kubeclient
::
HttpError
.
new
(
404
,
'Not found'
,
nil
))
end
it
{
is_expected
.
to
be_nil
}
end
...
...
This diff is collapsed.
Click to expand it.
spec/services/clusters/update_service_spec.rb
View file @
5ede567d
require
'spec_helper'
describe
Clusters
::
UpdateService
do
include
KubernetesHelpers
describe
'#execute'
do
subject
{
described_class
.
new
(
cluster
.
user
,
params
).
execute
(
cluster
)
}
...
...
@@ -34,6 +36,11 @@ describe Clusters::UpdateService do
}
end
before
do
allow
(
ClusterPlatformConfigureWorker
).
to
receive
(
:perform_async
)
stub_kubeclient_get_namespace
(
'https://kubernetes.example.com'
,
namespace:
'my-namespace'
)
end
it
'updates namespace'
do
is_expected
.
to
eq
(
true
)
expect
(
cluster
.
platform
.
namespace
).
to
eq
(
'custom-namespace'
)
...
...
This diff is collapsed.
Click to expand it.
spec/workers/cluster_platform_configure_worker_spec.rb
0 → 100644
View file @
5ede567d
# frozen_string_literal: true
require
'spec_helper'
describe
ClusterPlatformConfigureWorker
,
'#execute'
do
context
'when provider type is gcp'
do
let
(
:cluster
)
{
create
(
:cluster
,
:project
,
:provided_by_gcp
)
}
it
'configures kubernetes platform'
do
expect_any_instance_of
(
Clusters
::
Gcp
::
Kubernetes
::
CreateOrUpdateNamespaceService
).
to
receive
(
:execute
)
described_class
.
new
.
perform
(
cluster
.
id
)
end
end
context
'when provider type is user'
do
let
(
:cluster
)
{
create
(
:cluster
,
:project
,
:provided_by_user
)
}
it
'configures kubernetes platform'
do
expect_any_instance_of
(
Clusters
::
Gcp
::
Kubernetes
::
CreateOrUpdateNamespaceService
).
to
receive
(
:execute
)
described_class
.
new
.
perform
(
cluster
.
id
)
end
end
context
'when cluster does not exist'
do
it
'does not provision a cluster'
do
expect_any_instance_of
(
Clusters
::
Gcp
::
Kubernetes
::
CreateOrUpdateNamespaceService
).
not_to
receive
(
:execute
)
described_class
.
new
.
perform
(
123
)
end
end
end
This diff is collapsed.
Click to expand it.
spec/workers/cluster_provision_worker_spec.rb
View file @
5ede567d
...
...
@@ -14,18 +14,25 @@ describe ClusterProvisionWorker do
end
context
'when provider type is user'
do
let
(
:cluster
)
{
create
(
:cluster
,
provider_type: :
user
)
}
let
(
:cluster
)
{
create
(
:cluster
,
:provided_by_
user
)
}
it
'does not provision a cluster'
do
expect_any_instance_of
(
Clusters
::
Gcp
::
ProvisionService
).
not_to
receive
(
:execute
)
described_class
.
new
.
perform
(
cluster
.
id
)
end
it
'configures kubernetes platform'
do
expect
(
ClusterPlatformConfigureWorker
).
to
receive
(
:perform_async
).
with
(
cluster
.
id
)
described_class
.
new
.
perform
(
cluster
.
id
)
end
end
context
'when cluster does not exist'
do
it
'does not provision a cluster'
do
expect_any_instance_of
(
Clusters
::
Gcp
::
ProvisionService
).
not_to
receive
(
:execute
)
expect
(
ClusterPlatformConfigureWorker
).
not_to
receive
(
:perform_async
)
described_class
.
new
.
perform
(
123
)
end
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment