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
c4278602
Commit
c4278602
authored
Nov 07, 2017
by
Kamil Trzcinski
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/38464-k8s-apps' into add-ingress-to-cluster-applications
parents
18760259
02878cd9
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
208 additions
and
45 deletions
+208
-45
app/models/clusters/applications/helm.rb
app/models/clusters/applications/helm.rb
+4
-0
app/services/clusters/applications/base_helm_service.rb
app/services/clusters/applications/base_helm_service.rb
+4
-0
app/services/clusters/applications/check_installation_progress_service.rb
...sters/applications/check_installation_progress_service.rb
+3
-3
app/services/clusters/applications/install_service.rb
app/services/clusters/applications/install_service.rb
+1
-1
lib/gitlab/kubernetes/helm.rb
lib/gitlab/kubernetes/helm.rb
+42
-35
spec/factories/clusters/applications/helm.rb
spec/factories/clusters/applications/helm.rb
+1
-1
spec/features/projects/clusters_spec.rb
spec/features/projects/clusters_spec.rb
+42
-0
spec/lib/gitlab/kubernetes/helm_spec.rb
spec/lib/gitlab/kubernetes/helm_spec.rb
+100
-0
spec/models/clusters/applications/helm_spec.rb
spec/models/clusters/applications/helm_spec.rb
+6
-0
spec/serializers/cluster_application_entity_spec.rb
spec/serializers/cluster_application_entity_spec.rb
+1
-1
spec/serializers/cluster_entity_spec.rb
spec/serializers/cluster_entity_spec.rb
+2
-2
spec/services/clusters/applications/install_service_spec.rb
spec/services/clusters/applications/install_service_spec.rb
+2
-2
No files found.
app/models/clusters/applications/helm.rb
View file @
c4278602
...
@@ -26,6 +26,10 @@ module Clusters
...
@@ -26,6 +26,10 @@ module Clusters
def
name
def
name
self
.
class
.
application_name
self
.
class
.
application_name
end
end
def
install_command
Gitlab
::
Kubernetes
::
Helm
::
InstallCommand
.
new
(
name
,
true
)
end
end
end
end
end
end
end
app/services/clusters/applications/base_helm_service.rb
View file @
c4278602
...
@@ -20,6 +20,10 @@ module Clusters
...
@@ -20,6 +20,10 @@ module Clusters
def
helm_api
def
helm_api
@helm_api
||=
Gitlab
::
Kubernetes
::
Helm
.
new
(
kubeclient
)
@helm_api
||=
Gitlab
::
Kubernetes
::
Helm
.
new
(
kubeclient
)
end
end
def
install_command
@install_command
||=
app
.
install_command
end
end
end
end
end
end
end
app/services/clusters/applications/check_installation_progress_service.rb
View file @
c4278602
...
@@ -48,17 +48,17 @@ module Clusters
...
@@ -48,17 +48,17 @@ module Clusters
end
end
def
remove_installation_pod
def
remove_installation_pod
helm_api
.
delete_installation_pod!
(
app
)
helm_api
.
delete_installation_pod!
(
install_command
.
pod_name
)
rescue
rescue
# no-op
# no-op
end
end
def
installation_phase
def
installation_phase
helm_api
.
installation_status
(
app
)
helm_api
.
installation_status
(
install_command
.
pod_name
)
end
end
def
installation_errors
def
installation_errors
helm_api
.
installation_log
(
app
)
helm_api
.
installation_log
(
install_command
.
pod_name
)
end
end
end
end
end
end
...
...
app/services/clusters/applications/install_service.rb
View file @
c4278602
...
@@ -6,7 +6,7 @@ module Clusters
...
@@ -6,7 +6,7 @@ module Clusters
begin
begin
app
.
make_installing!
app
.
make_installing!
helm_api
.
install
(
app
)
helm_api
.
install
(
install_command
)
ClusterWaitForAppInstallationWorker
.
perform_in
(
ClusterWaitForAppInstallationWorker
.
perform_in
(
ClusterWaitForAppInstallationWorker
::
INTERVAL
,
app
.
name
,
app
.
id
)
ClusterWaitForAppInstallationWorker
::
INTERVAL
,
app
.
name
,
app
.
id
)
...
...
lib/gitlab/kubernetes/helm.rb
View file @
c4278602
...
@@ -3,27 +3,27 @@ module Gitlab
...
@@ -3,27 +3,27 @@ module Gitlab
class
Helm
class
Helm
HELM_VERSION
=
'2.7.0'
.
freeze
HELM_VERSION
=
'2.7.0'
.
freeze
NAMESPACE
=
'gitlab-managed-apps'
.
freeze
NAMESPACE
=
'gitlab-managed-apps'
.
freeze
COMMAND_SCRIPT
=
<<-
EOS
.
freeze
INSTALL_DEPS
=
<<-
EOS
.
freeze
set -eo pipefail
set -eo pipefail
apk add -U ca-certificates openssl >/dev/null
apk add -U ca-certificates openssl >/dev/null
wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v${HELM_VERSION}-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v${HELM_VERSION}-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
mv /tmp/linux-amd64/helm /usr/bin/
mv /tmp/linux-amd64/helm /usr/bin/
helm init ${HELM_INIT_OPTS} >/dev/null
[[ -z "${HELM_COMMAND+x}" ]] || helm ${HELM_COMMAND} >/dev/null
EOS
EOS
InstallCommand
=
Struct
.
new
(
:name
,
:install_helm
,
:chart
)
do
def
pod_name
"install-
#{
name
}
"
end
end
def
initialize
(
kubeclient
)
def
initialize
(
kubeclient
)
@kubeclient
=
kubeclient
@kubeclient
=
kubeclient
@namespace
=
Namespace
.
new
(
NAMESPACE
,
kubeclient
)
@namespace
=
Namespace
.
new
(
NAMESPACE
,
kubeclient
)
end
end
def
init!
def
install
(
command
)
install
(
OpenStruct
.
new
(
name:
'helm'
))
end
def
install
(
app
)
@namespace
.
ensure_exists!
@namespace
.
ensure_exists!
@kubeclient
.
create_pod
(
pod_resource
(
app
))
@kubeclient
.
create_pod
(
pod_resource
(
command
))
end
end
##
##
...
@@ -33,31 +33,27 @@ module Gitlab
...
@@ -33,31 +33,27 @@ module Gitlab
#
#
# values: "Pending", "Running", "Succeeded", "Failed", "Unknown"
# values: "Pending", "Running", "Succeeded", "Failed", "Unknown"
#
#
def
installation_status
(
app
)
def
installation_status
(
pod_name
)
@kubeclient
.
get_pod
(
pod_name
(
app
)
,
@namespace
.
name
).
status
.
phase
@kubeclient
.
get_pod
(
pod_name
,
@namespace
.
name
).
status
.
phase
end
end
def
installation_log
(
app
)
def
installation_log
(
pod_name
)
@kubeclient
.
get_pod_log
(
pod_name
(
app
)
,
@namespace
.
name
).
body
@kubeclient
.
get_pod_log
(
pod_name
,
@namespace
.
name
).
body
end
end
def
delete_installation_pod!
(
app
)
def
delete_installation_pod!
(
pod_name
)
@kubeclient
.
delete_pod
(
pod_name
(
app
)
,
@namespace
.
name
)
@kubeclient
.
delete_pod
(
pod_name
,
@namespace
.
name
)
end
end
private
private
def
pod_name
(
app
)
def
pod_resource
(
command
)
"install-
#{
app
.
name
}
"
labels
=
{
'gitlab.org/action'
:
'install'
,
'gitlab.org/application'
:
command
.
name
}
end
metadata
=
{
name:
command
.
pod_name
,
namespace:
@namespace
.
name
,
labels:
labels
}
def
pod_resource
(
app
)
labels
=
{
'gitlab.org/action'
:
'install'
,
'gitlab.org/application'
:
app
.
name
}
metadata
=
{
name:
pod_name
(
app
),
namespace:
@namespace
.
name
,
labels:
labels
}
container
=
{
container
=
{
name:
'helm'
,
name:
'helm'
,
image:
'alpine:3.6'
,
image:
'alpine:3.6'
,
env:
generate_pod_env
(
app
),
env:
generate_pod_env
(
command
),
command:
%w(/bin/sh)
,
command:
%w(/bin/sh)
,
args:
%w(-c $(COMMAND_SCRIPT))
args:
%w(-c $(COMMAND_SCRIPT))
}
}
...
@@ -66,23 +62,34 @@ module Gitlab
...
@@ -66,23 +62,34 @@ module Gitlab
::
Kubeclient
::
Resource
.
new
(
metadata:
metadata
,
spec:
spec
)
::
Kubeclient
::
Resource
.
new
(
metadata:
metadata
,
spec:
spec
)
end
end
def
generate_pod_env
(
app
)
def
generate_pod_env
(
command
)
env
=
{
{
HELM_VERSION
:
HELM_VERSION
,
HELM_VERSION
:
HELM_VERSION
,
TILLER_NAMESPACE
:
NAMESPACE
,
TILLER_NAMESPACE
:
@namespace
.
name
,
COMMAND_SCRIPT
:
COMMAND_SCRIPT
COMMAND_SCRIPT
:
generate_script
(
command
)
}
}.
map
{
|
key
,
value
|
{
name:
key
,
value:
value
}
}
end
if
app
.
name
!=
'helm'
def
generate_script
(
command
)
env
[
:HELM_INIT_OPTS
]
=
'--client-only'
[
env
[
:HELM_COMMAND
]
=
helm_install_comand
(
app
)
INSTALL_DEPS
,
helm_init_command
(
command
),
helm_install_command
(
command
)
].
join
(
"
\n
"
)
end
end
env
.
map
{
|
key
,
value
|
{
name:
key
,
value:
value
}
}
def
helm_init_command
(
command
)
if
command
.
install_helm
'helm init >/dev/null'
else
'helm init --client-only >/dev/null'
end
end
end
def
helm_install_command
(
command
)
return
if
command
.
chart
.
nil?
def
helm_install_comand
(
app
)
"helm install
#{
command
.
chart
}
--name
#{
command
.
name
}
--namespace
#{
@namespace
.
name
}
>/dev/null"
"install
#{
app
.
chart
}
--name
#{
app
.
name
}
--namespace
#{
NAMESPACE
}
"
end
end
end
end
end
end
...
...
spec/factories/clusters/applications/helm.rb
View file @
c4278602
...
@@ -3,7 +3,7 @@ FactoryGirl.define do
...
@@ -3,7 +3,7 @@ FactoryGirl.define do
cluster
factory:
%i(cluster provided_by_gcp)
cluster
factory:
%i(cluster provided_by_gcp)
trait
:not_installable
do
trait
:not_installable
do
status
-
2
status
(
-
2
)
end
end
trait
:installable
do
trait
:installable
do
...
...
spec/features/projects/clusters_spec.rb
View file @
c4278602
...
@@ -50,10 +50,22 @@ feature 'Clusters', :js do
...
@@ -50,10 +50,22 @@ feature 'Clusters', :js do
it
'user sees a cluster details page and creation status'
do
it
'user sees a cluster details page and creation status'
do
expect
(
page
).
to
have_content
(
'Cluster is being created on Google Container Engine...'
)
expect
(
page
).
to
have_content
(
'Cluster is being created on Google Container Engine...'
)
# Application Installation buttons
expect
(
page
.
find
(
:css
,
'.js-cluster-application-install-button'
)[
'disabled'
]).
to
eq
(
'true'
)
expect
(
page
.
find
(
:css
,
'.js-cluster-application-install-button'
).
text
).
to
eq
(
'Install'
)
Clusters
::
Cluster
.
last
.
provider
.
make_created!
Clusters
::
Cluster
.
last
.
provider
.
make_created!
expect
(
page
).
to
have_content
(
'Cluster was successfully created on Google Container Engine'
)
expect
(
page
).
to
have_content
(
'Cluster was successfully created on Google Container Engine'
)
end
end
it
'user sees a error if something worng during creation'
do
expect
(
page
).
to
have_content
(
'Cluster is being created on Google Container Engine...'
)
Clusters
::
Cluster
.
last
.
provider
.
make_errored!
(
'Something wrong!'
)
expect
(
page
).
to
have_content
(
'Something wrong!'
)
end
end
end
context
'when user filled form with invalid parameters'
do
context
'when user filled form with invalid parameters'
do
...
@@ -78,6 +90,36 @@ feature 'Clusters', :js do
...
@@ -78,6 +90,36 @@ feature 'Clusters', :js do
it
'user sees an cluster details page'
do
it
'user sees an cluster details page'
do
expect
(
page
).
to
have_button
(
'Save'
)
expect
(
page
).
to
have_button
(
'Save'
)
expect
(
page
.
find
(
:css
,
'.cluster-name'
).
value
).
to
eq
(
cluster
.
name
)
expect
(
page
.
find
(
:css
,
'.cluster-name'
).
value
).
to
eq
(
cluster
.
name
)
# Application Installation buttons
expect
(
page
.
find
(
:css
,
'.js-cluster-application-install-button'
)[
'disabled'
]).
to
be_nil
expect
(
page
.
find
(
:css
,
'.js-cluster-application-install-button'
)).
to
have_content
(
'Install'
)
end
context
'when user installs application: tiller'
do
before
do
allow
(
ClusterInstallAppWorker
).
to
receive
(
:perform_async
).
and_return
(
nil
)
page
.
find
(
:css
,
'.js-cluster-application-install-button'
).
click
end
it
'user sees status transition'
do
# FE sends request and gets the responce, then the buttons is "Install"
expect
(
page
.
find
(
:css
,
'.js-cluster-application-install-button'
)[
'disabled'
]).
to
eq
(
'true'
)
expect
(
page
.
find
(
:css
,
'.js-cluster-application-install-button'
)).
to
have_content
(
'Install'
)
Clusters
::
Cluster
.
last
.
application_helm
.
make_installing!
# FE starts pooling and update the buttons to "Installing"
expect
(
page
.
find
(
:css
,
'.js-cluster-application-install-button'
)[
'disabled'
]).
to
eq
(
'true'
)
expect
(
page
.
find
(
:css
,
'.js-cluster-application-install-button'
)).
to
have_content
(
'Installing'
)
Clusters
::
Cluster
.
last
.
application_helm
.
make_installed!
expect
(
page
.
find
(
:css
,
'.js-cluster-application-install-button'
)[
'disabled'
]).
to
eq
(
'true'
)
expect
(
page
.
find
(
:css
,
'.js-cluster-application-install-button'
)).
to
have_content
(
'Installed'
)
expect
(
page
).
to
have_content
(
'Helm Tiller was successfully installed on your cluster'
)
end
end
end
context
'when user disables the cluster'
do
context
'when user disables the cluster'
do
...
...
spec/lib/gitlab/kubernetes/helm_spec.rb
0 → 100644
View file @
c4278602
require
'spec_helper'
describe
Gitlab
::
Kubernetes
::
Helm
do
let
(
:client
)
{
double
(
'kubernetes client'
)
}
let
(
:helm
)
{
described_class
.
new
(
client
)
}
let
(
:namespace
)
{
Gitlab
::
Kubernetes
::
Namespace
.
new
(
described_class
::
NAMESPACE
,
client
)
}
let
(
:install_helm
)
{
true
}
let
(
:chart
)
{
'stable/a_chart'
}
let
(
:application_name
)
{
'app_name'
}
let
(
:command
)
{
Gitlab
::
Kubernetes
::
Helm
::
InstallCommand
.
new
(
application_name
,
install_helm
,
chart
)
}
subject
{
helm
}
before
do
allow
(
Gitlab
::
Kubernetes
::
Namespace
).
to
receive
(
:new
).
with
(
described_class
::
NAMESPACE
,
client
).
and_return
(
namespace
)
end
describe
'#initialize'
do
it
'creates a namespace object'
do
expect
(
Gitlab
::
Kubernetes
::
Namespace
).
to
receive
(
:new
).
with
(
described_class
::
NAMESPACE
,
client
)
subject
end
end
describe
'#install'
do
before
do
allow
(
client
).
to
receive
(
:create_pod
).
and_return
(
nil
)
allow
(
namespace
).
to
receive
(
:ensure_exists!
).
once
end
it
'ensures the namespace exists before creating the POD'
do
expect
(
namespace
).
to
receive
(
:ensure_exists!
).
once
.
ordered
expect
(
client
).
to
receive
(
:create_pod
).
once
.
ordered
subject
.
install
(
command
)
end
end
describe
'#installation_status'
do
let
(
:phase
)
{
Gitlab
::
Kubernetes
::
Pod
::
RUNNING
}
let
(
:pod
)
{
Kubeclient
::
Resource
.
new
(
status:
{
phase:
phase
})
}
# partial representation
it
'fetches POD phase from kubernetes cluster'
do
expect
(
client
).
to
receive
(
:get_pod
).
with
(
command
.
pod_name
,
described_class
::
NAMESPACE
).
once
.
and_return
(
pod
)
expect
(
subject
.
installation_status
(
command
.
pod_name
)).
to
eq
(
phase
)
end
end
describe
'#installation_log'
do
let
(
:log
)
{
'some output'
}
let
(
:response
)
{
RestClient
::
Response
.
new
(
log
)
}
it
'fetches POD phase from kubernetes cluster'
do
expect
(
client
).
to
receive
(
:get_pod_log
).
with
(
command
.
pod_name
,
described_class
::
NAMESPACE
).
once
.
and_return
(
response
)
expect
(
subject
.
installation_log
(
command
.
pod_name
)).
to
eq
(
log
)
end
end
describe
'#delete_installation_pod!'
do
it
'deletes the POD from kubernetes cluster'
do
expect
(
client
).
to
receive
(
:delete_pod
).
with
(
command
.
pod_name
,
described_class
::
NAMESPACE
).
once
subject
.
delete_installation_pod!
(
command
.
pod_name
)
end
end
describe
'#helm_init_command'
do
subject
{
helm
.
send
(
:helm_init_command
,
command
)
}
context
'when command.install_helm is true'
do
let
(
:install_helm
)
{
true
}
it
{
is_expected
.
to
eq
(
'helm init >/dev/null'
)
}
end
context
'when command.install_helm is false'
do
let
(
:install_helm
)
{
false
}
it
{
is_expected
.
to
eq
(
'helm init --client-only >/dev/null'
)
}
end
end
describe
'#helm_install_command'
do
subject
{
helm
.
send
(
:helm_install_command
,
command
)
}
context
'when command.chart is nil'
do
let
(
:chart
)
{
nil
}
it
{
is_expected
.
to
be_nil
}
end
context
'when command.chart is set'
do
let
(
:chart
)
{
'stable/a_chart'
}
it
{
is_expected
.
to
eq
(
"helm install
#{
chart
}
--name
#{
application_name
}
--namespace
#{
namespace
.
name
}
>/dev/null"
)}
end
end
end
spec/models/clusters/applications/helm_spec.rb
View file @
c4278602
...
@@ -38,6 +38,12 @@ describe Clusters::Applications::Helm do
...
@@ -38,6 +38,12 @@ describe Clusters::Applications::Helm do
end
end
end
end
describe
'#install_command'
do
it
'has all the needed information'
do
expect
(
subject
.
install_command
).
to
have_attributes
(
name:
subject
.
name
,
install_helm:
true
,
chart:
nil
)
end
end
describe
'status state machine'
do
describe
'status state machine'
do
describe
'#make_installing'
do
describe
'#make_installing'
do
subject
{
create
(
:cluster_applications_helm
,
:scheduled
)
}
subject
{
create
(
:cluster_applications_helm
,
:scheduled
)
}
...
...
spec/serializers/cluster_application_entity_spec.rb
View file @
c4278602
...
@@ -10,7 +10,7 @@ describe ClusterApplicationEntity do
...
@@ -10,7 +10,7 @@ describe ClusterApplicationEntity do
end
end
it
'has status'
do
it
'has status'
do
expect
(
subject
[
:status
]).
to
eq
(
:installable
)
expect
(
subject
[
:status
]).
to
eq
(
:
not_
installable
)
end
end
it
'has no status_reason'
do
it
'has no status_reason'
do
...
...
spec/serializers/cluster_entity_spec.rb
View file @
c4278602
...
@@ -39,12 +39,12 @@ describe ClusterEntity do
...
@@ -39,12 +39,12 @@ describe ClusterEntity do
let
(
:cluster
)
{
create
(
:cluster
)
}
let
(
:cluster
)
{
create
(
:cluster
)
}
subject
{
described_class
.
new
(
cluster
).
as_json
[
:applications
]}
subject
{
described_class
.
new
(
cluster
).
as_json
[
:applications
]}
it
'contains helm as installable'
do
it
'contains helm as
not_
installable'
do
expect
(
subject
).
not_to
be_empty
expect
(
subject
).
not_to
be_empty
helm
=
subject
[
0
]
helm
=
subject
[
0
]
expect
(
helm
[
:name
]).
to
eq
(
'helm'
)
expect
(
helm
[
:name
]).
to
eq
(
'helm'
)
expect
(
helm
[
:status
]).
to
eq
(
:installable
)
expect
(
helm
[
:status
]).
to
eq
(
:
not_
installable
)
end
end
end
end
end
end
...
...
spec/services/clusters/applications/install_service_spec.rb
View file @
c4278602
...
@@ -12,7 +12,7 @@ describe Clusters::Applications::InstallService do
...
@@ -12,7 +12,7 @@ describe Clusters::Applications::InstallService do
context
'when there are no errors'
do
context
'when there are no errors'
do
before
do
before
do
expect
(
helm_client
).
to
receive
(
:install
).
with
(
application
)
expect
(
helm_client
).
to
receive
(
:install
).
with
(
application
.
install_command
)
allow
(
ClusterWaitForAppInstallationWorker
).
to
receive
(
:perform_in
).
and_return
(
nil
)
allow
(
ClusterWaitForAppInstallationWorker
).
to
receive
(
:perform_in
).
and_return
(
nil
)
end
end
...
@@ -33,7 +33,7 @@ describe Clusters::Applications::InstallService do
...
@@ -33,7 +33,7 @@ describe Clusters::Applications::InstallService do
context
'when k8s cluster communication fails'
do
context
'when k8s cluster communication fails'
do
before
do
before
do
error
=
KubeException
.
new
(
500
,
'system failure'
,
nil
)
error
=
KubeException
.
new
(
500
,
'system failure'
,
nil
)
expect
(
helm_client
).
to
receive
(
:install
).
with
(
application
).
and_raise
(
error
)
expect
(
helm_client
).
to
receive
(
:install
).
with
(
application
.
install_command
).
and_raise
(
error
)
end
end
it
'make the application errored'
do
it
'make the application errored'
do
...
...
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