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
8a55d2c5
Commit
8a55d2c5
authored
Nov 21, 2017
by
Shinya Maeda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert KubernetesService logic in Platforms::Kubernetes
parent
25a3a183
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
258 additions
and
0 deletions
+258
-0
app/models/clusters/platforms/kubernetes.rb
app/models/clusters/platforms/kubernetes.rb
+123
-0
spec/models/clusters/platforms/kubernetes_spec.rb
spec/models/clusters/platforms/kubernetes_spec.rb
+135
-0
No files found.
app/models/clusters/platforms/kubernetes.rb
View file @
8a55d2c5
module
Clusters
module
Platforms
class
Kubernetes
<
ActiveRecord
::
Base
include
Gitlab
::
CurrentSettings
include
Gitlab
::
Kubernetes
include
ReactiveCaching
self
.
table_name
=
'cluster_platforms_kubernetes'
self
.
reactive_cache_key
=
->
(
kubernetes
)
{
[
kubernetes
.
class
.
model_name
.
singular
,
kubernetes
.
cluster_id
]
}
belongs_to
:cluster
,
inverse_of: :platform_kubernetes
,
class_name:
'Clusters::Cluster'
...
...
@@ -29,6 +34,8 @@ module Clusters
validates
:api_url
,
url:
true
,
presence:
true
validates
:token
,
presence:
true
after_save
:clear_reactive_cache!
# TODO: Glue code till we migrate Kubernetes Integration into Platforms::Kubernetes
after_destroy
:destroy_kubernetes_integration!
...
...
@@ -55,6 +62,80 @@ module Clusters
self
.
class
.
namespace_for_project
(
project
)
if
project
end
def
predefined_variables
config
=
YAML
.
dump
(
kubeconfig
)
variables
=
[
{
key:
'KUBE_URL'
,
value:
api_url
,
public:
true
},
{
key:
'KUBE_TOKEN'
,
value:
token
,
public:
false
},
{
key:
'KUBE_NAMESPACE'
,
value:
actual_namespace
,
public:
true
},
{
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
}
end
variables
end
# Constructs a list of terminals from the reactive cache
#
# Returns nil if the cache is empty, in which case you should try again a
# short time later
def
terminals
(
environment
)
with_reactive_cache
do
|
data
|
pods
=
filter_by_label
(
data
[
:pods
],
app:
environment
.
slug
)
terminals
=
pods
.
flat_map
{
|
pod
|
terminals_for_pod
(
api_url
,
actual_namespace
,
pod
)
}
terminals
.
each
{
|
terminal
|
add_terminal_auth
(
terminal
,
terminal_auth
)
}
end
end
# 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?
# We may want to cache extra things in the future
{
pods:
read_pods
}
end
def
kubeconfig
to_kubeconfig
(
url:
api_url
,
namespace:
actual_namespace
,
token:
token
,
ca_pem:
ca_pem
)
end
def
read_secrets
kubeclient
=
build_kubeclient!
kubeclient
.
get_secrets
.
as_json
end
# Returns a hash of all pods in the namespace
def
read_pods
kubeclient
=
build_kubeclient!
kubeclient
.
get_pods
(
namespace:
actual_namespace
).
as_json
rescue
KubeException
=>
err
raise
err
unless
err
.
error_code
==
404
[]
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
def
kubeclient
@kubeclient
||=
kubernetes_service
.
kubeclient
if
manages_kubernetes_service?
end
...
...
@@ -104,6 +185,48 @@ module Clusters
def
ensure_kubernetes_service
@kubernetes_service
||=
kubernetes_service
||
project
&
.
build_kubernetes_service
end
def
build_kubeclient!
(
api_path:
'api'
,
api_version:
'v1'
)
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
),
api_version
,
auth_options:
kubeclient_auth_options
,
ssl_options:
kubeclient_ssl_options
,
http_proxy_uri:
ENV
[
'http_proxy'
]
)
end
def
kubeclient_auth_options
return
{
username:
username
,
password:
password
}
if
username
&&
password
return
{
bearer_token:
token
}
if
token
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
terminal_auth
{
token:
token
,
ca_pem:
ca_pem
,
max_session_time:
current_application_settings
.
terminal_max_session_time
}
end
def
enforce_namespace_to_lower_case
self
.
namespace
=
self
.
namespace
&
.
downcase
end
end
end
end
spec/models/clusters/platforms/kubernetes_spec.rb
View file @
8a55d2c5
...
...
@@ -5,6 +5,8 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
include
ReactiveCachingHelpers
it
{
is_expected
.
to
belong_to
(
:cluster
)
}
it
{
is_expected
.
to
be_kind_of
(
Gitlab
::
Kubernetes
)
}
it
{
is_expected
.
to
be_kind_of
(
ReactiveCaching
)
}
it
{
is_expected
.
to
respond_to
:ca_pem
}
describe
'before_validation'
do
...
...
@@ -185,4 +187,137 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
it
{
is_expected
.
to
be_nil
}
end
end
describe
'#predefined_variables'
do
let!
(
:cluster
)
{
create
(
:cluster
,
:project
,
platform_kubernetes:
kubernetes
)
}
let
(
:kubernetes
)
{
create
(
: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
.
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
(
{
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
}
)
end
end
context
'namespace is provided'
do
let
(
:namespace
)
{
'my-project'
}
before
do
kubernetes
.
namespace
=
namespace
end
it_behaves_like
'setting variables'
end
context
'no namespace provided'
do
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
describe
'#terminals'
do
subject
{
service
.
terminals
(
environment
)
}
let!
(
:cluster
)
{
create
(
:cluster
,
:project
,
platform_kubernetes:
service
)
}
let
(
:project
)
{
cluster
.
project
}
let
(
:service
)
{
create
(
:platform_kubernetes
,
:configured
)
}
let
(
:environment
)
{
build
(
:environment
,
project:
project
,
name:
"env"
,
slug:
"env-000000"
)
}
context
'with invalid pods'
do
it
'returns no terminals'
do
stub_reactive_cache
(
service
,
pods:
[{
"bad"
=>
"pod"
}])
is_expected
.
to
be_empty
end
end
context
'with valid pods'
do
let
(
:pod
)
{
kube_pod
(
app:
environment
.
slug
)
}
let
(
:terminals
)
{
kube_terminals
(
service
,
pod
)
}
before
do
stub_reactive_cache
(
service
,
pods:
[
pod
,
pod
,
kube_pod
(
app:
"should-be-filtered-out"
)]
)
end
it
'returns terminals'
do
is_expected
.
to
eq
(
terminals
+
terminals
)
end
it
'uses max session time from settings'
do
stub_application_setting
(
terminal_max_session_time:
600
)
times
=
subject
.
map
{
|
terminal
|
terminal
[
:max_session_time
]
}
expect
(
times
).
to
eq
[
600
,
600
,
600
,
600
]
end
end
end
describe
'#calculate_reactive_cache'
do
subject
{
service
.
calculate_reactive_cache
}
let!
(
:cluster
)
{
create
(
:cluster
,
:project
,
enabled:
enabled
,
platform_kubernetes:
service
)
}
let
(
:service
)
{
create
(
:platform_kubernetes
,
:configured
)
}
let
(
:enabled
)
{
true
}
context
'when cluster is disabled'
do
let
(
:enabled
)
{
false
}
it
{
is_expected
.
to
be_nil
}
end
context
'when kubernetes responds with valid pods'
do
before
do
stub_kubeclient_pods
end
it
{
is_expected
.
to
eq
(
pods:
[
kube_pod
])
}
end
context
'when kubernetes responds with 500s'
do
before
do
stub_kubeclient_pods
(
status:
500
)
end
it
{
expect
{
subject
}.
to
raise_error
(
KubeException
)
}
end
context
'when kubernetes responds with 404s'
do
before
do
stub_kubeclient_pods
(
status:
404
)
end
it
{
is_expected
.
to
eq
(
pods:
[])
}
end
end
end
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