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
1
Merge Requests
1
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
nexedi
gitlab-ce
Commits
2d1a77b8
Commit
2d1a77b8
authored
Oct 01, 2017
by
Shinya Maeda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert KubernetesService. Introduce FetchKubernetesTokenService.
parent
e499c1c3
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
127 additions
and
84 deletions
+127
-84
app/models/ci/cluster.rb
app/models/ci/cluster.rb
+5
-3
app/models/project_services/kubernetes_service.rb
app/models/project_services/kubernetes_service.rb
+2
-16
app/services/ci/create_cluster_service.rb
app/services/ci/create_cluster_service.rb
+4
-0
app/services/ci/fetch_kubernetes_token_service.rb
app/services/ci/fetch_kubernetes_token_service.rb
+70
-0
app/services/ci/integrate_cluster_service.rb
app/services/ci/integrate_cluster_service.rb
+11
-16
app/services/ci/update_cluster_service.rb
app/services/ci/update_cluster_service.rb
+5
-9
app/views/projects/clusters/_form.html.haml
app/views/projects/clusters/_form.html.haml
+1
-1
app/workers/wait_for_cluster_creation_worker.rb
app/workers/wait_for_cluster_creation_worker.rb
+23
-36
lib/google_api/cloud_platform/client.rb
lib/google_api/cloud_platform/client.rb
+6
-3
No files found.
app/models/ci/cluster.rb
View file @
2d1a77b8
...
@@ -33,13 +33,15 @@ module Ci
...
@@ -33,13 +33,15 @@ module Ci
}
}
def
error!
(
reason
)
def
error!
(
reason
)
update!
(
status:
statuses
[
:errored
],
update!
(
status:
statuses
[
:errored
],
status_reason:
reason
,
gcp_token:
nil
)
status_reason:
reason
,
gcp_token:
nil
)
end
end
def
on_creation?
def
on_creation?
scheduled?
||
creating?
scheduled?
||
creating?
end
end
def
api_url
'https://'
+
endpoint
end
end
end
end
end
app/models/project_services/kubernetes_service.rb
View file @
2d1a77b8
...
@@ -15,7 +15,6 @@ class KubernetesService < DeploymentService
...
@@ -15,7 +15,6 @@ class KubernetesService < DeploymentService
# Bearer authentication
# Bearer authentication
# TODO: user/password auth, client certificates
# TODO: user/password auth, client certificates
prop_accessor
:token
prop_accessor
:token
attr_accessor
:username
,
:password
# Provide a custom CA bundle for self-signed deployments
# Provide a custom CA bundle for self-signed deployments
prop_accessor
:ca_pem
prop_accessor
:ca_pem
...
@@ -139,15 +138,6 @@ class KubernetesService < DeploymentService
...
@@ -139,15 +138,6 @@ class KubernetesService < DeploymentService
TEMPLATE_PLACEHOLDER
=
'Kubernetes namespace'
.
freeze
TEMPLATE_PLACEHOLDER
=
'Kubernetes namespace'
.
freeze
def
read_secrets
kubeclient
=
build_kubeclient!
kubeclient
.
get_secrets
.
as_json
rescue
KubeException
=>
err
raise
err
unless
err
.
error_code
==
404
[]
end
private
private
def
kubeconfig
def
kubeconfig
...
@@ -167,7 +157,7 @@ class KubernetesService < DeploymentService
...
@@ -167,7 +157,7 @@ class KubernetesService < DeploymentService
end
end
def
build_kubeclient!
(
api_path:
'api'
,
api_version:
'v1'
)
def
build_kubeclient!
(
api_path:
'api'
,
api_version:
'v1'
)
raise
"Incomplete settings"
unless
api_url
&&
(
token
||
(
username
&&
password
))
raise
"Incomplete settings"
unless
api_url
&&
actual_namespace
&&
token
::
Kubeclient
::
Client
.
new
(
::
Kubeclient
::
Client
.
new
(
join_api_url
(
api_path
),
join_api_url
(
api_path
),
...
@@ -200,11 +190,7 @@ class KubernetesService < DeploymentService
...
@@ -200,11 +190,7 @@ class KubernetesService < DeploymentService
end
end
def
kubeclient_auth_options
def
kubeclient_auth_options
if
token
{
bearer_token:
token
}
{
bearer_token:
token
}
else
{
username:
username
,
password:
password
}
end
end
end
def
join_api_url
(
api_path
)
def
join_api_url
(
api_path
)
...
...
app/services/ci/create_cluster_service.rb
View file @
2d1a77b8
module
Ci
module
Ci
class
CreateClusterService
<
BaseService
class
CreateClusterService
<
BaseService
def
execute
(
access_token
)
def
execute
(
access_token
)
if
params
[
'machine_type'
].
blank?
params
[
'machine_type'
]
=
GoogleApi
::
CloudPlatform
::
Client
::
DEFAULT_MACHINE_TYPE
end
project
.
clusters
.
create
(
project
.
clusters
.
create
(
params
.
merge
(
user:
current_user
,
params
.
merge
(
user:
current_user
,
status:
Ci
::
Cluster
.
statuses
[
:scheduled
],
status:
Ci
::
Cluster
.
statuses
[
:scheduled
],
...
...
app/services/ci/fetch_kubernetes_token_service.rb
0 → 100644
View file @
2d1a77b8
##
# TODO:
# Almost components in this class were copied from app/models/project_services/kubernetes_service.rb
# We should dry up those classes not to repeat the same code.
# Maybe we should have a special facility (e.g. lib/kubernetes_api) to maintain all Kubernetes API caller.
module
Ci
class
FetchKubernetesTokenService
attr_reader
:api_url
,
:ca_pem
,
:username
,
:password
def
initialize
(
api_url
,
ca_pem
,
username
,
password
)
@api_url
=
api_url
@ca_pem
=
ca_pem
@username
=
username
@password
=
password
end
def
execute
read_secrets
.
each
do
|
secret
|
name
=
secret
.
dig
(
'metadata'
,
'name'
)
if
/default-token/
=~
name
token_base64
=
secret
.
dig
(
'data'
,
'token'
)
return
Base64
.
decode64
(
token_base64
)
if
token_base64
end
end
end
private
def
read_secrets
kubeclient
=
build_kubeclient!
kubeclient
.
get_secrets
.
as_json
rescue
KubeException
=>
err
raise
err
unless
err
.
error_code
==
404
[]
end
def
build_kubeclient!
(
api_path:
'api'
,
api_version:
'v1'
)
raise
"Incomplete settings"
unless
api_url
&&
username
&&
password
::
Kubeclient
::
Client
.
new
(
join_api_url
(
api_path
),
api_version
,
auth_options:
{
username:
username
,
password:
password
},
ssl_options:
kubeclient_ssl_options
,
http_proxy_uri:
ENV
[
'http_proxy'
]
)
end
def
join_api_url
(
api_path
)
url
=
URI
.
parse
(
api_url
)
prefix
=
url
.
path
.
sub
(
%r{/+
\z
}
,
''
)
url
.
path
=
[
prefix
,
api_path
].
join
(
"/"
)
url
.
to_s
end
def
kubeclient_ssl_options
opts
=
{
verify_ssl:
OpenSSL
::
SSL
::
VERIFY_PEER
}
if
ca_pem
.
present?
opts
[
:cert_store
]
=
OpenSSL
::
X509
::
Store
.
new
opts
[
:cert_store
].
add_cert
(
OpenSSL
::
X509
::
Certificate
.
new
(
ca_pem
))
end
opts
end
end
end
app/services/ci/integrate_cluster_service.rb
View file @
2d1a77b8
module
Ci
module
Ci
class
IntegrateClusterService
class
IntegrateClusterService
def
execute
(
cluster
,
endpoint
,
ca_cert
,
token
,
username
,
password
)
def
execute
(
cluster
,
endpoint
,
ca_cert
,
token
,
username
,
password
)
kubernetes_service
||=
cluster
.
project
.
find_or_initialize_service
(
'kubernetes'
)
Ci
::
Cluster
.
transaction
do
Ci
::
Cluster
.
transaction
do
# Update service
kubernetes_service
||=
kubernetes_service
.
attributes
=
{
cluster
.
project
.
find_or_initialize_service
(
'kubernetes'
)
active:
true
,
api_url:
endpoint
,
ca_pem:
ca_cert
,
namespace:
cluster
.
project_namespace
,
token:
token
}
kubernetes_service
.
save!
# Save info in cluster record
cluster
.
update!
(
cluster
.
update!
(
enabled:
true
,
enabled:
true
,
service:
kubernetes_service
,
service:
kubernetes_service
,
...
@@ -25,10 +14,16 @@ module Ci
...
@@ -25,10 +14,16 @@ module Ci
ca_cert:
ca_cert
,
ca_cert:
ca_cert
,
endpoint:
endpoint
,
endpoint:
endpoint
,
gcp_token:
nil
,
gcp_token:
nil
,
status:
Ci
::
Cluster
.
statuses
[
:created
]
gcp_operation_id:
nil
,
)
status:
Ci
::
Cluster
.
statuses
[
:created
])
end
kubernetes_service
.
update!
(
active:
true
,
api_url:
cluster
.
api_url
,
ca_pem:
ca_cert
,
namespace:
cluster
.
project_namespace
,
token:
token
)
end
rescue
ActiveRecord
::
RecordInvalid
=>
e
rescue
ActiveRecord
::
RecordInvalid
=>
e
cluster
.
error!
(
"Failed to integrate cluster into kubernetes_service:
#{
e
.
message
}
"
)
cluster
.
error!
(
"Failed to integrate cluster into kubernetes_service:
#{
e
.
message
}
"
)
end
end
...
...
app/services/ci/update_cluster_service.rb
View file @
2d1a77b8
...
@@ -2,22 +2,18 @@ module Ci
...
@@ -2,22 +2,18 @@ module Ci
class
UpdateClusterService
<
BaseService
class
UpdateClusterService
<
BaseService
def
execute
(
cluster
)
def
execute
(
cluster
)
Ci
::
Cluster
.
transaction
do
Ci
::
Cluster
.
transaction
do
if
params
[
'enabled'
]
==
'true'
cluster
.
update!
(
enabled:
params
[
'enabled'
])
cluster
.
service
.
attributes
=
{
if
params
[
'enabled'
]
==
'true'
cluster
.
service
.
update!
(
active:
true
,
active:
true
,
api_url:
cluster
.
endpoint
,
api_url:
cluster
.
api_url
,
ca_pem:
cluster
.
ca_cert
,
ca_pem:
cluster
.
ca_cert
,
namespace:
cluster
.
project_namespace
,
namespace:
cluster
.
project_namespace
,
token:
cluster
.
kubernetes_token
token:
cluster
.
kubernetes_token
)
}
cluster
.
service
.
save!
else
else
cluster
.
service
.
update
(
active:
false
)
cluster
.
service
.
update
(
active:
false
)
end
end
cluster
.
update!
(
enabled:
params
[
'enabled'
])
end
end
rescue
ActiveRecord
::
RecordInvalid
=>
e
rescue
ActiveRecord
::
RecordInvalid
=>
e
cluster
.
errors
.
add
(
:base
,
e
.
message
)
cluster
.
errors
.
add
(
:base
,
e
.
message
)
...
...
app/views/projects/clusters/_form.html.haml
View file @
2d1a77b8
...
@@ -33,4 +33,4 @@
...
@@ -33,4 +33,4 @@
=
field
.
submit
s_
(
'ClusterIntegration|Create cluster'
),
class:
'btn btn-save'
=
field
.
submit
s_
(
'ClusterIntegration|Create cluster'
),
class:
'btn btn-save'
-# TODO: Remove before merge
-# TODO: Remove before merge
=
link_to
"Create on Google Container Engine"
,
namespace_project_clusters_path
(
@project
.
namespace
,
@project
,
cluster:
{
cluster_name:
"gke-test-creation
#{
Random
.
rand
(
100
)
}
"
,
gcp_project_id:
'gitlab-internal-153318'
,
cluster_zone:
'us-central1-a'
,
cluster_size:
'1'
,
project_namespace:
'aaa'
,
machine_type:
'???'
}),
method: :post
=
link_to
"Create on Google Container Engine"
,
namespace_project_clusters_path
(
@project
.
namespace
,
@project
,
cluster:
{
cluster_name:
"gke-test-creation
#{
Random
.
rand
(
100
)
}
"
,
gcp_project_id:
'gitlab-internal-153318'
,
cluster_zone:
'us-central1-a'
,
cluster_size:
'1'
,
project_namespace:
'aaa'
,
machine_type:
'n1-standard-1'
}),
method: :post
\ No newline at end of file
\ No newline at end of file
app/workers/wait_for_cluster_creation_worker.rb
View file @
2d1a77b8
...
@@ -17,69 +17,56 @@ class WaitForClusterCreationWorker
...
@@ -17,69 +17,56 @@ class WaitForClusterCreationWorker
GoogleApi
::
CloudPlatform
::
Client
.
new
(
cluster
.
gcp_token
,
nil
)
GoogleApi
::
CloudPlatform
::
Client
.
new
(
cluster
.
gcp_token
,
nil
)
operation
=
api_client
.
projects_zones_operations
(
operation
=
api_client
.
projects_zones_operations
(
cluster
.
gcp_project_id
,
cluster
.
gcp_project_id
,
cluster
.
cluster_zone
,
cluster
.
cluster_zone
,
cluster
.
gcp_operation_id
cluster
.
gcp_operation_id
)
)
if
operation
.
is_a?
(
StandardError
)
if
operation
.
is_a?
(
StandardError
)
return
cluster
.
error!
(
"Failed to request to CloudPlatform;
#{
operation
.
message
}
"
)
return
cluster
.
error!
(
"Failed to request to CloudPlatform;
#{
operation
.
message
}
"
)
end
end
case
operation
.
status
case
operation
.
status
when
'DONE'
integrate
(
api_client
,
cluster
)
when
'RUNNING'
when
'RUNNING'
if
Time
.
now
<
operation
.
start_time
.
to_time
+
TIMEOUT
if
Time
.
now
<
operation
.
start_time
.
to_time
+
TIMEOUT
WaitForClusterCreationWorker
.
perform_in
(
EAGER_INTERVAL
,
cluster
.
id
)
WaitForClusterCreationWorker
.
perform_in
(
EAGER_INTERVAL
,
cluster
.
id
)
else
else
return
cluster
.
error!
(
"Cluster creation time exceeds timeout;
#{
TIMEOUT
}
"
)
return
cluster
.
error!
(
"Cluster creation time exceeds timeout;
#{
TIMEOUT
}
"
)
end
end
when
'DONE'
integrate
(
cluster
,
api_client
)
else
else
return
cluster
.
error!
(
"Unexpected operation status;
#{
operation
.
status_message
}
"
)
return
cluster
.
error!
(
"Unexpected operation status;
#{
operation
.
status
}
#{
operation
.
status
_message
}
"
)
end
end
end
end
def
integrate
(
api_client
,
cluster
)
def
integrate
(
cluster
,
api_client
)
# Get cluster details (end point, etc)
gke_cluster
=
api_client
.
projects_zones_clusters_get
(
gke_cluster
=
api_client
.
projects_zones_clusters_get
(
cluster
.
gcp_project_id
,
cluster
.
gcp_project_id
,
cluster
.
cluster_zone
,
cluster
.
cluster_zone
,
cluster
.
cluster_name
cluster
.
cluster_name
)
)
if
gke_cluster
.
is_a?
(
StandardError
)
if
gke_cluster
.
is_a?
(
StandardError
)
return
cluster
.
error!
(
"Failed to request to CloudPlatform;
#{
gke_cluster
.
message
}
"
)
return
cluster
.
error!
(
"Failed to request to CloudPlatform;
#{
gke_cluster
.
message
}
"
)
end
end
# Get k8s token
begin
kubernetes_token
=
''
endpoint
=
gke_cluster
.
endpoint
KubernetesService
.
new
.
tap
do
|
ks
|
api_url
=
'https://'
+
endpoint
ks
.
api_url
=
'https://'
+
gke_cluster
.
endpoint
ca_cert
=
Base64
.
decode64
(
gke_cluster
.
master_auth
.
cluster_ca_certificate
)
ks
.
ca_pem
=
Base64
.
decode64
(
gke_cluster
.
master_auth
.
cluster_ca_certificate
)
username
=
gke_cluster
.
master_auth
.
username
ks
.
username
=
gke_cluster
.
master_auth
.
username
password
=
gke_cluster
.
master_auth
.
password
ks
.
password
=
gke_cluster
.
master_auth
.
password
rescue
Exception
=>
e
secrets
=
ks
.
read_secrets
return
cluster
.
error!
(
"Can not extract the extected data;
#{
e
}
"
)
secrets
.
each
do
|
secret
|
name
=
secret
.
dig
(
'metadata'
,
'name'
)
if
/default-token/
=~
name
token_base64
=
secret
.
dig
(
'data'
,
'token'
)
kubernetes_token
=
Base64
.
decode64
(
token_base64
)
break
end
end
end
end
kubernetes_token
=
Ci
::
FetchKubernetesTokenService
.
new
(
api_url
,
ca_cert
,
username
,
password
).
execute
unless
kubernetes_token
unless
kubernetes_token
return
cluster
.
error!
(
'Failed to get a default token of kubernetes'
)
return
cluster
.
error!
(
'Failed to get a default token of kubernetes'
)
end
end
# k8s endpoint, ca_cert
Ci
::
IntegrateClusterService
.
new
.
execute
(
endpoint
=
'https://'
+
gke_cluster
.
endpoint
cluster
,
endpoint
,
ca_cert
,
kubernetes_token
,
username
,
password
)
ca_cert
=
Base64
.
decode64
(
gke_cluster
.
master_auth
.
cluster_ca_certificate
)
username
=
gke_cluster
.
master_auth
.
username
password
=
gke_cluster
.
master_auth
.
password
Ci
::
IntegrateClusterService
.
new
.
execute
(
cluster
,
endpoint
,
ca_cert
,
kubernetes_token
,
username
,
password
)
end
end
end
end
lib/google_api/cloud_platform/client.rb
View file @
2d1a77b8
...
@@ -3,6 +3,8 @@ require 'google/apis/container_v1'
...
@@ -3,6 +3,8 @@ require 'google/apis/container_v1'
module
GoogleApi
module
GoogleApi
module
CloudPlatform
module
CloudPlatform
class
Client
<
GoogleApi
::
Auth
class
Client
<
GoogleApi
::
Auth
DEFAULT_MACHINE_TYPE
=
'n1-standard-1'
class
<<
self
class
<<
self
def
session_key_for_token
def
session_key_for_token
:cloud_platform_access_token
:cloud_platform_access_token
...
@@ -27,8 +29,6 @@ module GoogleApi
...
@@ -27,8 +29,6 @@ module GoogleApi
cluster
cluster
end
end
# Responce exmaple
# TODO: machine_type : Defailt 3.75 GB
def
projects_zones_clusters_create
(
project_id
,
zone
,
cluster_name
,
cluster_size
,
machine_type
:)
def
projects_zones_clusters_create
(
project_id
,
zone
,
cluster_name
,
cluster_size
,
machine_type
:)
service
=
Google
::
Apis
::
ContainerV1
::
ContainerService
.
new
service
=
Google
::
Apis
::
ContainerV1
::
ContainerService
.
new
service
.
authorization
=
access_token
service
.
authorization
=
access_token
...
@@ -37,7 +37,10 @@ module GoogleApi
...
@@ -37,7 +37,10 @@ module GoogleApi
{
{
"cluster"
:
{
"cluster"
:
{
"name"
:
cluster_name
,
"name"
:
cluster_name
,
"initial_node_count"
:
cluster_size
"initial_node_count"
:
cluster_size
,
"node_config"
:
{
"machine_type"
:
machine_type
# Default 3.75 GB, if ommit
}
}
}
}
}
)
)
...
...
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