Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
heptapod
heptapod
Commits
d4e359134fc0
Commit
d4e35913
authored
Oct 23, 2017
by
Shinya Maeda
Browse files
This works
parent
580af3249709
Changes
27
Hide whitespace changes
Inline
Side-by-side
app/controllers/projects/clusters_controller.rb
View file @
d4e35913
...
...
@@ -27,7 +27,13 @@
end
def
new
@cluster
=
project
.
build_cluster
@cluster
=
Clusters
::
Cluster
.
new
(
platform_type: :kubernetes
,
provider_type: :gcp
).
tap
do
|
cluster
|
cluster
.
build_provider_gcp
cluster
.
build_platform_kubernetes
cluster
.
projects
<<
project
end
end
def
create
...
...
@@ -31,7 +37,7 @@
end
def
create
@cluster
=
C
i
::
CreateService
@cluster
=
C
lusters
::
CreateService
.
new
(
project
,
current_user
,
create_params
)
.
execute
(
token_in_session
)
...
...
@@ -58,7 +64,7 @@
end
def
update
C
i
::
Update
Cluster
Service
C
lusters
::
UpdateService
.
new
(
project
,
current_user
,
update_params
)
.
execute
(
cluster
)
...
...
@@ -89,5 +95,6 @@
def
create_params
params
.
require
(
:cluster
).
permit
(
:enabled
,
:name
,
:platform_type
,
:provider_type
,
...
...
@@ -92,5 +99,5 @@
:platform_type
,
:provider_type
,
kubernetes_
platform
:
[
platform_
kubernetes_
attributes
:
[
:namespace
],
...
...
@@ -95,10 +102,9 @@
:namespace
],
gcp_provider:
[
:project_id
,
:cluster_zone
,
:cluster_name
,
:cluster_size
,
provider_gcp_attributes:
[
:gcp_project_id
,
:zone
,
:num_nodes
,
:machine_type
])
end
...
...
@@ -106,7 +112,7 @@
def
update_params
params
.
require
(
:cluster
).
permit
(
:enabled
,
kubernetes_
platform
:
[
platform_
kubernetes_
attributes
:
[
:namespace
])
end
...
...
app/models/clusters/cluster.rb
View file @
d4e35913
...
...
@@ -2,4 +2,6 @@
class
Cluster
<
ActiveRecord
::
Base
include
Presentable
self
.
table_name
=
'clusters'
belongs_to
:user
...
...
@@ -5,3 +7,2 @@
belongs_to
:user
belongs_to
:service
...
...
@@ -7,5 +8,5 @@
enum
:
platform_type
{
enum
platform_type
:
{
kubernetes:
1
}
...
...
@@ -9,8 +10,8 @@
kubernetes:
1
}
enum
:
provider_type
{
enum
provider_type
:
{
user:
0
,
gcp:
1
}
...
...
@@ -13,10 +14,7 @@
user:
0
,
gcp:
1
}
has_many
:cluster_projects
has_many
:projects
,
through: :cluster_projects
has_one
:gcp_provider
has_one
:kubernetes_platform
has_many
:cluster_projects
,
class_name:
'Clusters::Project'
has_many
:projects
,
through: :cluster_projects
,
class_name:
'::Project'
...
...
@@ -22,4 +20,4 @@
a
ccept
s_ne
sted_attributes_for
:gcp_provider
accepts_
ne
s
te
d_attributes_for
:kubernetes_platform
h
as_
o
ne
:provider_gcp
,
class_name:
'Clusters::Providers::Gcp'
has_one
:platform_kuber
nete
s
,
class_name:
'Clusters::Platforms::Kubernetes'
...
...
@@ -25,7 +23,9 @@
validates
:kubernetes_platform
,
presence:
true
,
if: :kubernetes?
validates
:gcp_provider
,
presence:
true
,
if: :gcp?
accepts_nested_attributes_for
:provider_gcp
accepts_nested_attributes_for
:platform_kubernetes
validates
:name
,
cluster_name:
true
validate
:restrict_modification
,
on: :update
delegate
:status
,
to: :provider
,
allow_nil:
true
delegate
:status_reason
,
to: :provider
,
allow_nil:
true
...
...
@@ -28,7 +28,29 @@
validate
:restrict_modification
,
on: :update
delegate
:status
,
to: :provider
,
allow_nil:
true
delegate
:status_reason
,
to: :provider
,
allow_nil:
true
delegate
:status_name
,
to: :provider
,
allow_nil:
true
delegate
:on_creation?
,
to: :provider
,
allow_nil:
true
def
provider
return
provider_gcp
if
gcp?
end
def
platform
return
platform_kubernetes
if
kubernetes?
end
def
project
first_project
end
def
first_project
return
@first_project
if
defined?
(
@first_project
)
@first_project
=
projects
.
first
end
private
def
restrict_modification
if
provider
&
.
on_creation?
...
...
@@ -38,19 +60,5 @@
true
end
def
provider
return
gcp_provider
if
gcp?
end
def
platform
return
kubernetes_platform
if
kubernetes?
end
def
first_project
return
@first_project
if
defined?
(
@first_project
)
@first_project
=
projects
.
first
end
end
end
app/models/clusters/cluster_project.rb
deleted
100644 → 0
View file @
580af324
module
Clusters
class
ClusterProject
<
ActiveRecord
::
Base
belongs_to
:cluster
belongs_to
:project
end
end
app/models/clusters/platforms/kubernetes.rb
View file @
d4e35913
...
...
@@ -4,5 +4,7 @@
include
Gitlab
::
Kubernetes
include
ReactiveCaching
self
.
table_name
=
'cluster_platforms_kubernetes'
TEMPLATE_PLACEHOLDER
=
'Kubernetes namespace'
.
freeze
...
...
@@ -7,4 +9,4 @@
TEMPLATE_PLACEHOLDER
=
'Kubernetes namespace'
.
freeze
self
.
reactive_cache_key
=
->
(
service
)
{
[
service
.
class
.
model_name
.
singular
,
service
.
project
_id
]
}
self
.
reactive_cache_key
=
->
(
kubernetes
)
{
[
kubernetes
.
class
.
model_name
.
singular
,
kubernetes
.
cluster
_id
]
}
...
...
@@ -10,5 +12,5 @@
belongs_to
:cluster
belongs_to
:cluster
,
inverse_of: :platform_kubernetes
,
class_name:
'Clusters::Cluster'
attr_encrypted
:password
,
mode: :per_attribute_iv
,
...
...
@@ -28,8 +30,8 @@
message:
Gitlab
::
Regex
.
kubernetes_namespace_regex_message
}
validates
:api_url
,
url:
true
,
presence:
true
validates
:token
,
presence:
true
validates
:api_url
,
url:
true
,
presence:
true
,
on: :update
validates
:token
,
presence:
true
,
on: :update
after_save
:clear_reactive_cache!
...
...
@@ -53,9 +55,9 @@
{
key:
'KUBECONFIG'
,
value:
config
,
public:
false
,
file:
true
}
]
if
ca_
pem
.
present?
variables
<<
{
key:
'KUBE_CA_PEM'
,
value:
ca_
pem
,
public:
true
}
variables
<<
{
key:
'KUBE_CA_PEM_FILE'
,
value:
ca_
pem
,
public:
true
,
file:
true
}
if
ca_
cert
.
present?
variables
<<
{
key:
'KUBE_CA_PEM'
,
value:
ca_
cert
,
public:
true
}
variables
<<
{
key:
'KUBE_CA_PEM_FILE'
,
value:
ca_
cert
,
public:
true
,
file:
true
}
end
variables
...
...
@@ -76,7 +78,7 @@
# Caches resources in the namespace so other calls don't need to block on
# network access
def
calculate_reactive_cache
return
unless
active?
&&
project
&&
!
project
.
pending_delete?
return
unless
active?
&&
cluster
.
project
&&
!
cluster
.
project
.
pending_delete?
# We may want to cache extra things in the future
{
pods:
read_pods
}
...
...
@@ -87,10 +89,10 @@
url:
api_url
,
namespace:
actual_namespace
,
token:
token
,
ca_pem:
ca_
pem
)
ca_pem:
ca_
cert
)
end
def
namespace_placeholder
default_namespace
||
TEMPLATE_PLACEHOLDER
end
...
...
@@ -91,11 +93,12 @@
end
def
namespace_placeholder
default_namespace
||
TEMPLATE_PLACEHOLDER
end
def
default_namespace
"
#{
cluster
.
first_project
.
path
}
-
#{
cluster
.
first_project
.
id
}
"
if
cluster
.
first_project
def
default_namespace
(
project
=
nil
)
project
||=
cluster
&
.
project
"
#{
project
.
path
}
-
#{
project
.
id
}
"
if
project
end
def
read_secrets
...
...
@@ -120,5 +123,5 @@
def
kubeclient_ssl_options
opts
=
{
verify_ssl:
OpenSSL
::
SSL
::
VERIFY_PEER
}
if
ca_
pem
.
present?
if
ca_
cert
.
present?
opts
[
:cert_store
]
=
OpenSSL
::
X509
::
Store
.
new
...
...
@@ -124,5 +127,5 @@
opts
[
:cert_store
]
=
OpenSSL
::
X509
::
Store
.
new
opts
[
:cert_store
].
add_cert
(
OpenSSL
::
X509
::
Certificate
.
new
(
ca_
pem
))
opts
[
:cert_store
].
add_cert
(
OpenSSL
::
X509
::
Certificate
.
new
(
ca_
cert
))
end
opts
...
...
@@ -131,7 +134,11 @@
private
def
build_kubeclient!
(
api_path:
'api'
,
api_version:
'v1'
)
raise
"Incomplete settings"
unless
api_url
&&
actual_namespace
&&
token
raise
"Incomplete settings"
unless
api_url
&&
actual_namespace
unless
(
username
&&
password
)
||
token
raise
"Either username/password or token is required to access API"
end
::
Kubeclient
::
Client
.
new
(
join_api_url
(
api_path
),
...
...
@@ -143,7 +150,7 @@
end
def
kubeclient_auth_options
return
{
username:
username
,
password:
password
}
if
username
return
{
username:
username
,
password:
password
}
if
username
&&
password
return
{
bearer_token:
token
}
if
token
end
...
...
@@ -159,7 +166,7 @@
def
terminal_auth
{
token:
token
,
ca_pem:
ca_
pem
,
ca_pem:
ca_
cert
,
max_session_time:
current_application_settings
.
terminal_max_session_time
}
end
...
...
app/models/clusters/project.rb
0 → 100644
View file @
d4e35913
module
Clusters
class
Project
<
ActiveRecord
::
Base
self
.
table_name
=
'cluster_projects'
belongs_to
:cluster
,
inverse_of: :projects
,
class_name:
'Clusters::Cluster'
belongs_to
:project
,
inverse_of: :project
,
class_name:
'Project'
end
end
app/models/clusters/providers/gcp.rb
View file @
d4e35913
module
Clusters
module
Providers
class
Gcp
<
ActiveRecord
::
Base
b
el
ongs_to
:cluster
s
el
f
.
table_name
=
'cluster_providers_gcp'
...
...
@@ -5,6 +5,8 @@
default_value_for
:cluster_zone
,
'us-central1-a'
default_value_for
:cluster_size
,
3
belongs_to
:cluster
,
inverse_of: :provider_gcp
,
class_name:
'Clusters::Cluster'
default_value_for
:zone
,
'us-central1-a'
default_value_for
:num_nodes
,
3
default_value_for
:machine_type
,
'n1-standard-4'
attr_encrypted
:access_token
,
...
...
@@ -12,10 +14,10 @@
key:
Gitlab
::
Application
.
secrets
.
db_key_base
,
algorithm:
'aes-256-cbc'
validates
:project_id
,
validates
:
gcp_
project_id
,
length:
1
..
63
,
format:
{
with:
Gitlab
::
Regex
.
kubernetes_namespace_regex
,
message:
Gitlab
::
Regex
.
kubernetes_namespace_regex_message
}
...
...
@@ -16,13 +18,8 @@
length:
1
..
63
,
format:
{
with:
Gitlab
::
Regex
.
kubernetes_namespace_regex
,
message:
Gitlab
::
Regex
.
kubernetes_namespace_regex_message
}
validates
:cluster_name
,
length:
1
..
63
,
format:
{
with:
Gitlab
::
Regex
.
kubernetes_namespace_regex
,
message:
Gitlab
::
Regex
.
kubernetes_namespace_regex_message
}
validates
:zone
,
presence:
true
...
...
@@ -28,7 +25,5 @@
validates
:cluster_zone
,
presence:
true
validates
:cluster_size
,
validates
:num_nodes
,
presence:
true
,
numericality:
{
only_integer:
true
,
...
...
@@ -54,5 +49,5 @@
end
before_transition
any
=>
[
:errored
,
:created
]
do
|
provider
|
provider
.
token
=
nil
provider
.
access_
token
=
nil
provider
.
operation_id
=
nil
...
...
@@ -58,5 +53,9 @@
provider
.
operation_id
=
nil
provider
.
save!
end
before_transition
any
=>
[
:creating
]
do
|
provider
,
transition
|
operation_id
=
transition
.
args
.
first
provider
.
operation_id
=
operation_id
if
operation_id
end
before_transition
any
=>
[
:errored
]
do
|
provider
,
transition
|
...
...
app/models/project.rb
View file @
d4e35913
...
...
@@ -178,8 +178,8 @@
has_one
:project_feature
,
inverse_of: :project
has_one
:statistics
,
class_name:
'ProjectStatistics'
has_
many
:cluster_project
s
,
class_name:
'Clusters::
Cluster
Project'
has_one
:cluster
,
through: :cluster_project
s
has_
one
:cluster_project
,
class_name:
'Clusters::Project'
has_one
:cluster
,
through: :cluster_project
,
class_name:
'Clusters::Cluster'
# Container repositories need to remove data from the container registry,
# which is not managed by the DB. Hence we're still using dependent: :destroy
...
...
app/policies/clusters/cluster_policy.rb
0 → 100644
View file @
d4e35913
module
Clusters
class
ClusterPolicy
<
BasePolicy
alias_method
:cluster
,
:subject
delegate
{
cluster
.
project
}
rule
{
can?
(
:master_access
)
}.
policy
do
enable
:update_cluster
enable
:admin_cluster
end
end
end
app/policies/gcp/cluster_policy.rb
deleted
100644 → 0
View file @
580af324
module
Gcp
class
ClusterPolicy
<
BasePolicy
alias_method
:cluster
,
:subject
delegate
{
@subject
.
project
}
rule
{
can?
(
:master_access
)
}.
policy
do
enable
:update_cluster
enable
:admin_cluster
end
end
end
app/presenters/clusters/cluster_presenter.rb
0 → 100644
View file @
d4e35913
module
Clusters
class
ClusterPresenter
<
Gitlab
::
View
::
Presenter
::
Delegated
presents
:cluster
def
gke_cluster_url
"https://console.cloud.google.com/kubernetes/clusters/details/
#{
provider
.
zone
}
/
#{
name
}
"
if
gcp?
end
end
end
app/presenters/gcp/cluster_presenter.rb
deleted
100644 → 0
View file @
580af324
module
Gcp
class
ClusterPresenter
<
Gitlab
::
View
::
Presenter
::
Delegated
presents
:cluster
def
gke_cluster_url
"https://console.cloud.google.com/kubernetes/clusters/details/
#{
gcp_cluster_zone
}
/
#{
gcp_cluster_name
}
"
end
end
end
app/services/clusters/create_service.rb
View file @
d4e35913
module
Clusters
class
CreateService
<
BaseService
def
execute
(
access_token
)
params
[
'gcp_machine_type'
]
||=
GoogleApi
::
CloudPlatform
::
Client
::
DEFAULT_MACHINE_TYPE
attr_reader
:access_token
...
...
@@ -5,4 +4,4 @@
cluster_params
=
params
.
merge
(
user:
current_user
)
def
execute
(
access_token
)
@access_token
=
access_token
...
...
@@ -8,5 +7,5 @@
project
.
create_cluster
(
cluster_params
)
.
tap
do
|
cluster
|
create_cluster
.
tap
do
|
cluster
|
ClusterProvisionWorker
.
perform_async
(
cluster
.
id
)
if
cluster
.
persisted?
end
end
...
...
@@ -10,5 +9,31 @@
ClusterProvisionWorker
.
perform_async
(
cluster
.
id
)
if
cluster
.
persisted?
end
end
private
def
create_cluster
cluster
=
nil
ActiveRecord
::
Base
.
transaction
do
cluster
=
Clusters
::
Cluster
.
create!
(
cluster_params
)
cluster
.
projects
<<
project
end
cluster
rescue
ActiveRecord
::
RecordInvalid
=>
e
e
.
record
end
def
cluster_params
return
@cluster_params
if
defined?
(
@cluster_params
)
params
[
:provider_gcp_attributes
][
:machine_type
]
||=
GoogleApi
::
CloudPlatform
::
Client
::
DEFAULT_MACHINE_TYPE
params
[
:provider_gcp_attributes
][
:access_token
]
||=
access_token
@cluster_params
=
params
.
merge
(
user:
current_user
)
end
end
end
app/services/clusters/gcp/fetch_operation_service.rb
View file @
d4e35913
...
...
@@ -3,9 +3,9 @@
class
FetchOperationService
def
execute
(
provider
)
operation
=
provider
.
api_client
.
projects_zones_operations
(
provider
.
project_id
,
provider
.
cluster_
zone
,
provider
.
gcp_
project_id
,
provider
.
zone
,
provider
.
operation_id
)
yield
(
operation
)
if
block_given?
rescue
Google
::
Apis
::
ServerError
,
Google
::
Apis
::
ClientError
,
Google
::
Apis
::
AuthorizationError
=>
e
...
...
@@ -8,8 +8,8 @@
provider
.
operation_id
)
yield
(
operation
)
if
block_given?
rescue
Google
::
Apis
::
ServerError
,
Google
::
Apis
::
ClientError
,
Google
::
Apis
::
AuthorizationError
=>
e
return
provider
.
make_errored!
(
"Failed to request to CloudPlatform;
#{
e
.
message
}
"
)
provider
.
make_errored!
(
"Failed to request to CloudPlatform;
#{
e
.
message
}
"
)
end
end
end
...
...
app/services/clusters/gcp/finalize_creation_service.rb
View file @
d4e35913
...
...
@@ -7,7 +7,6 @@
@provider
=
provider
configure_provider
configure_kubernetes_platform
request_kuberenetes_platform_token
configure_kubernetes
ActiveRecord
::
Base
.
transaction
do
...
...
@@ -12,6 +11,6 @@
ActiveRecord
::
Base
.
transaction
do
kubernetes
_platform
.
updat
e!
kubernetes
.
sav
e!
provider
.
make_created!
end
rescue
Google
::
Apis
::
ServerError
,
Google
::
Apis
::
ClientError
,
Google
::
Apis
::
AuthorizationError
=>
e
...
...
@@ -15,7 +14,7 @@
provider
.
make_created!
end
rescue
Google
::
Apis
::
ServerError
,
Google
::
Apis
::
ClientError
,
Google
::
Apis
::
AuthorizationError
=>
e
return
cluster
.
make_errored!
(
"Failed to request to CloudPlatform;
#{
e
.
message
}
"
)
cluster
.
make_errored!
(
"Failed to request to CloudPlatform;
#{
e
.
message
}
"
)
rescue
ActiveRecord
::
RecordInvalid
=>
e
cluster
.
make_errored!
(
"Failed to configure GKE Cluster:
#{
e
.
message
}
"
)
end
...
...
@@ -26,11 +25,11 @@
provider
.
endpoint
=
gke_cluster
.
endpoint
end
def
configure_kubernetes
_platform
kubernetes
_platform
=
cluster
.
kubernetes_platform
kubernetes
_platform
.
api_url
=
'https://'
+
endpoint
kubernetes
_platform
.
ca_cert
=
Base64
.
decode64
(
gke_cluster
.
master_auth
.
cl
us
t
er
_ca_certificate
)
kubernetes
_platform
.
username
=
gke_cluster
.
master_auth
.
username
kubernetes
_platform
.
password
=
gke_cluster
.
master_auth
.
password
def
configure_kubernetes
kubernetes
.
api_url
=
'https://'
+
gke_cluster
.
endpoint
kubernetes
.
ca_cert
=
Base64
.
decode64
(
gke_cluster
.
master_auth
.
cluster_ca_certificate
)
kubernetes
.
username
=
gke_cluster
.
master_auth
.
user
name
kubernetes
.
password
=
gke_cluster
.
master_auth
.
password
kubernetes
.
token
=
request_kuberenetes_token
end
...
...
@@ -35,7 +34,7 @@
end
def
request_kuberenetes_
platform_
token
kubernetes
_platform
.
read_secrets
.
each
do
|
secret
|
def
request_kuberenetes_token
kubernetes
.
read_secrets
.
each
do
|
secret
|
name
=
secret
.
dig
(
'metadata'
,
'name'
)
if
/default-token/
=~
name
token_base64
=
secret
.
dig
(
'data'
,
'token'
)
...
...
@@ -39,10 +38,7 @@
name
=
secret
.
dig
(
'metadata'
,
'name'
)
if
/default-token/
=~
name
token_base64
=
secret
.
dig
(
'data'
,
'token'
)
if
token_base64
kubernetes_platform
.
token
=
Base64
.
decode64
(
token_base64
)
break
end
return
Base64
.
decode64
(
token_base64
)
if
token_base64
end
end
end
...
...
@@ -50,8 +46,8 @@
def
gke_cluster
@gke_cluster
||=
provider
.
api_client
.
projects_zones_clusters_get
(
provider
.
gcp_project_id
,
provider
.
gcp_cluster_
zone
,
provider
.
gcp_
cluster
_
name
)
provider
.
zone
,
cluster
.
name
)
end
def
cluster
...
...
@@ -55,6 +51,6 @@
end
def
cluster
provider
.
cluster
@cluster
||=
provider
.
cluster
end
...
...
@@ -59,7 +55,7 @@
end
def
kubernetes
_platform
cluster
.
kubernetes
_platform
def
kubernetes
@
kubernetes
||=
cluster
.
platform_kubernetes
end
end
end
...
...
app/services/clusters/gcp/provision_service.rb
View file @
d4e35913
...
...
@@ -6,12 +6,12 @@
def
execute
(
provider
)
@provider
=
provider
unless
operation
.
status
==
'RUNNING'
||
operation
.
status
==
'PENDING'
return
provider
.
make_
errored!
(
"Operation status is unexpected;
#{
operation
.
status_message
}
"
)
end