Commit 080c604e authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab-ce master

parents df650a0f b4f4edd4
...@@ -94,10 +94,13 @@ The plan for the upcoming milestone must be finalized by the 1st of the month, o ...@@ -94,10 +94,13 @@ The plan for the upcoming milestone must be finalized by the 1st of the month, o
## Feature freeze on the 7th for the release on the 22nd ## Feature freeze on the 7th for the release on the 22nd
After 7th at 23:59 (Pacific Time Zone) of each month, RC1 of the upcoming After 7th at 23:59 (Pacific Time Zone) of each month, stable branch and RC1
release (to be shipped on the 22nd) is created and deployed to GitLab.com and of the upcoming release (to be shipped on the 22nd) is created and deployed to GitLab.com.
the stable branch for this release is frozen, which means master is no longer The stable branch is frozen at the most recent "qualifying commit" on master.
merged into it. Merge requests may still be merged into master during this A "qualifying commit" is one that is pushed before the feature freeze cutoff time
and that passes all CI jobs (green pipeline).
Merge requests may still be merged into master during this
period, but they will go into the _next_ release, unless they are manually period, but they will go into the _next_ release, unless they are manually
cherry-picked into the stable branch. cherry-picked into the stable branch.
......
<script>
import { mapState, mapActions } from 'vuex';
import { GlModal } from '@gitlab/ui';
/**
* This component keeps the GlModal's visibility in sync with the given vuex module.
*/
export default {
components: {
GlModal,
},
props: {
modalId: {
type: String,
required: true,
},
modalModule: {
type: String,
required: true,
},
},
computed: {
...mapState({
isVisible(state) {
return state[this.modalModule].isVisible;
},
}),
attrs() {
const { modalId, modalModule, ...attrs } = this.$attrs;
return attrs;
},
},
watch: {
isVisible(val) {
return val ? this.bsShow() : this.bsHide();
},
},
methods: {
...mapActions({
syncShow(dispatch) {
return dispatch(`${this.modalModule}/show`);
},
syncHide(dispatch) {
return dispatch(`${this.modalModule}/hide`);
},
}),
bsShow() {
this.$root.$emit('bv::show::modal', this.modalId);
},
bsHide() {
// $root.$emit is a workaround because other b-modal approaches don't work yet with gl-modal
this.$root.$emit('bv::hide::modal', this.modalId);
},
},
};
</script>
<template>
<gl-modal
v-bind="attrs"
:modal-id="modalId"
v-on="$listeners"
@shown="syncShow"
@hidden="syncHide"
>
<slot></slot>
</gl-modal>
</template>
import * as types from './mutation_types';
export const open = ({ commit }, data) => {
commit(types.OPEN, data);
};
export const close = ({ commit }) => {
commit(types.CLOSE);
};
export const show = ({ commit }) => {
commit(types.SHOW);
};
export const hide = ({ commit }) => {
commit(types.HIDE);
};
import state from './state';
import mutations from './mutations';
import * as actions from './actions';
export default () => ({
namespaced: true,
state: state(),
mutations,
actions,
});
export const HIDE = 'HIDE';
export const SHOW = 'SHOW';
export const OPEN = 'OPEN';
export const CLOSE = 'CLOSE';
import * as types from './mutation_types';
export default {
[types.SHOW](state) {
state.isVisible = true;
},
[types.HIDE](state) {
state.isVisible = false;
},
[types.OPEN](state, data) {
state.data = data;
state.isVisible = true;
},
[types.CLOSE](state) {
state.data = null;
state.isVisible = false;
},
};
export default () => ({
isVisible: false,
data: null,
});
...@@ -635,7 +635,7 @@ module Ci ...@@ -635,7 +635,7 @@ module Ci
def all_merge_requests def all_merge_requests
@all_merge_requests ||= @all_merge_requests ||=
if merge_request? if merge_request?
project.merge_requests.where(id: merge_request.id) project.merge_requests.where(id: merge_request_id)
else else
project.merge_requests.where(source_branch: ref) project.merge_requests.where(source_branch: ref)
end end
...@@ -714,6 +714,12 @@ module Ci ...@@ -714,6 +714,12 @@ module Ci
def git_ref def git_ref
if merge_request? if merge_request?
##
# In the future, we're going to change this ref to
# merge request's merged reference, such as "refs/merge-requests/:iid/merge".
# In order to do that, we have to update GitLab-Runner's source pulling
# logic.
# See https://gitlab.com/gitlab-org/gitlab-runner/merge_requests/1092
Gitlab::Git::BRANCH_REF_PREFIX + ref.to_s Gitlab::Git::BRANCH_REF_PREFIX + ref.to_s
else else
super super
......
...@@ -65,6 +65,8 @@ module Clusters ...@@ -65,6 +65,8 @@ module Clusters
abac: 2 abac: 2
} }
default_value_for :authorization_type, :rbac
def actual_namespace def actual_namespace
if namespace.present? if namespace.present?
namespace namespace
......
...@@ -330,8 +330,8 @@ class Project < ActiveRecord::Base ...@@ -330,8 +330,8 @@ class Project < ActiveRecord::Base
validates :star_count, numericality: { greater_than_or_equal_to: 0 } validates :star_count, numericality: { greater_than_or_equal_to: 0 }
validate :check_limit, on: :create validate :check_limit, on: :create
validate :check_repository_path_availability, on: :update, if: ->(project) { project.renamed? } validate :check_repository_path_availability, on: :update, if: ->(project) { project.renamed? }
validate :visibility_level_allowed_by_group validate :visibility_level_allowed_by_group, if: -> { changes.has_key?(:visibility_level) }
validate :visibility_level_allowed_as_fork validate :visibility_level_allowed_as_fork, if: -> { changes.has_key?(:visibility_level) }
validate :check_wiki_path_conflict validate :check_wiki_path_conflict
validate :validate_pages_https_only, if: -> { changes.has_key?(:pages_https_only) } validate :validate_pages_https_only, if: -> { changes.has_key?(:pages_https_only) }
validates :repository_storage, validates :repository_storage,
......
= _('Environment variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use environment variables for passwords, secret keys, or whatever you want.') = _('Environment variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use environment variables for passwords, secret keys, or whatever you want.')
= _('You may also add variables that are made available to the running application by prepending the variable key with <code>K8S_SECRET_</code>.').html_safe
= link_to _('More information'), help_page_path('ci/variables/README', anchor: 'variables')
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
- if current_user_menu?(:help) - if current_user_menu?(:help)
%li %li
= link_to _("Help"), help_path = link_to _("Help"), help_path
%li.divider
%li
= link_to _("Submit feedback"), "https://about.gitlab.com/submit-feedback"
- if current_user_menu?(:help) || current_user_menu?(:settings) || current_user_menu?(:profile) - if current_user_menu?(:help) || current_user_menu?(:settings) || current_user_menu?(:profile)
= render 'shared/user_dropdown_contributing_link' = render 'shared/user_dropdown_contributing_link'
- if instance_review_permitted? - if instance_review_permitted?
......
---
title: Add submit feedback link to help dropdown
merge_request: 23547
author:
type: added
---
title: Configure Auto DevOps deployed applications with secrets from prefixed CI variables
merge_request: 23719
author:
type: added
---
title: Make RBAC enabled default for new clusters
merge_request: 24119
author:
type: changed
---
title: Add indexes to speed up CI query.
merge_request: 23188
author:
type: performance
---
title: Only validate project visibility when it has changed
merge_request: 24142
author:
type: fixed
...@@ -131,6 +131,9 @@ module ActiveRecord ...@@ -131,6 +131,9 @@ module ActiveRecord
using = inddef.scan(/USING (.+?) /).flatten[0].to_sym using = inddef.scan(/USING (.+?) /).flatten[0].to_sym
opclasses = Hash[inddef.scan(/\((.+?)\)(?:$| WHERE )/).flatten[0].split(',').map do |column_and_opclass| opclasses = Hash[inddef.scan(/\((.+?)\)(?:$| WHERE )/).flatten[0].split(',').map do |column_and_opclass|
column, opclass = column_and_opclass.split(' ').map(&:strip) column, opclass = column_and_opclass.split(' ').map(&:strip)
end.reject do |column, opclass|
['desc', 'asc'].include?(opclass&.downcase)
end.map do |column, opclass|
[column, opclass] if opclass [column, opclass] if opclass
end.compact] end.compact]
...@@ -151,6 +154,9 @@ module ActiveRecord ...@@ -151,6 +154,9 @@ module ActiveRecord
def quoted_columns_for_index(column_names, options = {}) def quoted_columns_for_index(column_names, options = {})
column_opclasses = options[:opclasses] || {} column_opclasses = options[:opclasses] || {}
column_names.map {|name| "#{quote_column_name(name)} #{column_opclasses[name]}"} column_names.map {|name| "#{quote_column_name(name)} #{column_opclasses[name]}"}
quoted_columns = Hash[column_names.map { |name| [name.to_sym, "#{quote_column_name(name)} #{column_opclasses[name]}"] }]
add_options_for_index_columns(quoted_columns, options).values
end end
end end
end end
......
# frozen_string_literal: true
class AddIndexesToCiBuildsAndPipelines < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
indexes.each do |index|
add_concurrent_index(*index)
end
end
def down
indexes.each do |index|
remove_concurrent_index(*index)
end
end
private
def indexes
[
[
:ci_pipelines,
[:project_id, :ref, :id],
{
order: { id: :desc },
name: 'index_ci_pipelines_on_project_idandrefandiddesc'
}
],
[
:ci_builds,
[:commit_id, :artifacts_expire_at, :id],
{
where: "type::text = 'Ci::Build'::text AND (retried = false OR retried IS NULL) AND (name::text = ANY (ARRAY['sast'::character varying, 'dependency_scanning'::character varying, 'sast:container'::character varying, 'container_scanning'::character varying, 'dast'::character varying]::text[]))",
name: 'index_ci_builds_on_commit_id_and_artifacts_expireatandidpartial'
}
]
]
end
end
# frozen_string_literal: true
class MakeLegacyFalseDefault < ActiveRecord::Migration[5.0]
DOWNTIME = false
def change
change_column_default :cluster_providers_gcp, :legacy_abac, from: true, to: false
end
end
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20181220165848) do ActiveRecord::Schema.define(version: 20190103140724) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -443,6 +443,7 @@ ActiveRecord::Schema.define(version: 20181220165848) do ...@@ -443,6 +443,7 @@ ActiveRecord::Schema.define(version: 20181220165848) do
t.string "token_encrypted" t.string "token_encrypted"
t.index ["artifacts_expire_at"], name: "index_ci_builds_on_artifacts_expire_at", where: "(artifacts_file <> ''::text)", using: :btree t.index ["artifacts_expire_at"], name: "index_ci_builds_on_artifacts_expire_at", where: "(artifacts_file <> ''::text)", using: :btree
t.index ["auto_canceled_by_id"], name: "index_ci_builds_on_auto_canceled_by_id", using: :btree t.index ["auto_canceled_by_id"], name: "index_ci_builds_on_auto_canceled_by_id", using: :btree
t.index ["commit_id", "artifacts_expire_at", "id"], name: "index_ci_builds_on_commit_id_and_artifacts_expireatandidpartial", where: "(((type)::text = 'Ci::Build'::text) AND ((retried = false) OR (retried IS NULL)) AND ((name)::text = ANY (ARRAY[('sast'::character varying)::text, ('dependency_scanning'::character varying)::text, ('sast:container'::character varying)::text, ('container_scanning'::character varying)::text, ('dast'::character varying)::text])))", using: :btree
t.index ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree t.index ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree
t.index ["commit_id", "status", "type"], name: "index_ci_builds_on_commit_id_and_status_and_type", using: :btree t.index ["commit_id", "status", "type"], name: "index_ci_builds_on_commit_id_and_status_and_type", using: :btree
t.index ["commit_id", "type", "name", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_name_and_ref", using: :btree t.index ["commit_id", "type", "name", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_name_and_ref", using: :btree
...@@ -586,6 +587,7 @@ ActiveRecord::Schema.define(version: 20181220165848) do ...@@ -586,6 +587,7 @@ ActiveRecord::Schema.define(version: 20181220165848) do
t.index ["merge_request_id"], name: "index_ci_pipelines_on_merge_request_id", where: "(merge_request_id IS NOT NULL)", using: :btree t.index ["merge_request_id"], name: "index_ci_pipelines_on_merge_request_id", where: "(merge_request_id IS NOT NULL)", using: :btree
t.index ["pipeline_schedule_id"], name: "index_ci_pipelines_on_pipeline_schedule_id", using: :btree t.index ["pipeline_schedule_id"], name: "index_ci_pipelines_on_pipeline_schedule_id", using: :btree
t.index ["project_id", "iid"], name: "index_ci_pipelines_on_project_id_and_iid", unique: true, where: "(iid IS NOT NULL)", using: :btree t.index ["project_id", "iid"], name: "index_ci_pipelines_on_project_id_and_iid", unique: true, where: "(iid IS NOT NULL)", using: :btree
t.index ["project_id", "ref", "id"], name: "index_ci_pipelines_on_project_idandrefandiddesc", order: { id: :desc }, using: :btree
t.index ["project_id", "ref", "status", "id"], name: "index_ci_pipelines_on_project_id_and_ref_and_status_and_id", using: :btree t.index ["project_id", "ref", "status", "id"], name: "index_ci_pipelines_on_project_id_and_ref_and_status_and_id", using: :btree
t.index ["project_id", "sha"], name: "index_ci_pipelines_on_project_id_and_sha", using: :btree t.index ["project_id", "sha"], name: "index_ci_pipelines_on_project_id_and_sha", using: :btree
t.index ["project_id", "source"], name: "index_ci_pipelines_on_project_id_and_source", using: :btree t.index ["project_id", "source"], name: "index_ci_pipelines_on_project_id_and_source", using: :btree
...@@ -746,7 +748,7 @@ ActiveRecord::Schema.define(version: 20181220165848) do ...@@ -746,7 +748,7 @@ ActiveRecord::Schema.define(version: 20181220165848) do
t.string "endpoint" t.string "endpoint"
t.text "encrypted_access_token" t.text "encrypted_access_token"
t.string "encrypted_access_token_iv" t.string "encrypted_access_token_iv"
t.boolean "legacy_abac", default: true, null: false t.boolean "legacy_abac", default: false, null: false
t.index ["cluster_id"], name: "index_cluster_providers_gcp_on_cluster_id", unique: true, using: :btree t.index ["cluster_id"], name: "index_cluster_providers_gcp_on_cluster_id", unique: true, using: :btree
end end
......
# Auto Deploy: quick start guide This document was moved to [another location](../../topics/autodevops/index.md#auto-deploy).
This is a step-by-step guide to deploying a project hosted on GitLab.com to Google Cloud, using Auto Deploy.
We made a minimal [Ruby application](https://gitlab.com/gitlab-examples/minimal-ruby-app) to use as an example for this guide. It contains two files:
* `server.rb` - our application. It will start an HTTP server on port 5000 and render “Hello, world!”
* `Dockerfile` - to build our app into a container image. It will use a ruby base image and run `server.rb`
## Fork sample project on GitLab.com
Let’s start by forking our sample application. Go to [the project page](https://gitlab.com/gitlab-examples/minimal-ruby-app) and press the `Fork` button. Soon you should have a project under your namespace with the necessary files.
## Set up your own cluster on Google Kubernetes Engine
If you do not already have a Google Cloud account, create one at https://console.cloud.google.com.
Visit the [`Kubernetes Engine`](https://console.cloud.google.com/kubernetes/list) tab and create a new cluster. You can change the name and leave the rest of the default settings. Once you have your cluster running, you need to connect to the cluster by following the Google interface.
## Connect to Kubernetes cluster
You need to have the Google Cloud SDK installed. e.g.
On OSX, install [homebrew](https://brew.sh):
1. Install Brew Caskroom: `brew install caskroom/cask/brew-cask`
1. Install Google Cloud SDK: `brew cask install google-cloud-sdk`
1. Add `kubectl`: `gcloud components install kubectl`
1. Log in: `gcloud auth login`
Now go back to the Google interface, find your cluster, and follow the instructions under `Connect to the cluster` and open the Kubernetes Dashboard. It will look something like `gcloud container clusters get-credentials ruby-autodeploy \ --zone europe-west2-c --project api-project-XXXXXXX` and then `kubectl proxy`.
![connect to cluster](img/guide_connect_cluster.png)
## Copy credentials to GitLab.com project
Once you have the Kubernetes Dashboard interface running, you should visit `Secrets` under the `Config` section. There you should find the settings we need for GitLab integration: ca.crt and token.
![connect to cluster](img/guide_secret.png)
You need to copy-paste the ca.crt and token into your project on GitLab.com in the Kubernetes integration page under project `Settings` > `Integrations` > `Project services` > `Kubernetes`. Don't actually copy the namespace though. Each project should have a unique namespace, and by leaving it blank, GitLab will create one for you.
![connect to cluster](img/guide_integration.png)
For API URL, you should use the `Endpoint` IP from your cluster page on Google Cloud Platform.
## Expose the application to the internet
In order to be able to visit your application, you need to install an NGINX ingress controller and point your domain name to its external IP address.
### Set up Ingress controller
You’ll need to make sure you have an ingress controller. If you don’t have one, do:
```sh
brew install kubernetes-helm
helm init
helm install --name ruby-app stable/nginx-ingress
```
This should create several services including `ruby-app-nginx-ingress-controller`. You can list your services by running `kubectl get svc` to confirm that.
### Point DNS at Cluster IP
Find out the external IP address of the `ruby-app-nginx-ingress-controller` by running:
```sh
kubectl get svc ruby-app-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
```
Use this IP address to configure your DNS. This part heavily depends on your preferences and domain provider. But in case you are not sure, just create an A record with a wildcard host like `*.<your-domain>` pointing to the external IP address you found above.
Use `nslookup minimal-ruby-app-staging.<yourdomain>` to confirm that domain is assigned to the cluster IP.
## Set up Auto Deploy
Visit the home page of your GitLab.com project and press "Set up Auto Deploy" button.
![auto deploy button](img/auto_deploy_btn.png)
You will be redirected to the "New file" page where you can apply one of the Auto Deploy templates. Select "Kubernetes" to apply the template, then in the file, replace `domain.example.com` with your domain name and make any other adjustments you need.
![auto deploy template](img/auto_deploy_dropdown.png)
Change the target branch to `master`, and submit your changes. This should create
a new pipeline with several jobs. If you made only the domain name change, the
pipeline will have three jobs: `build`, `staging`, and `production`.
The `build` job will create a Docker image with your new change and push it to
the GitLab Container Registry. The `staging` job will deploy this image on your
cluster. Once the deploy job succeeds you should be able to see your application by
visiting the Kubernetes dashboard. Select the namespace of your project, which
will look like `ruby-autodeploy-23`, but with a unique ID for your project, and
your app will be listed as "staging" under the "Deployment" tab.
Once its ready - just visit http://minimal-ruby-app-staging.yourdomain.com to see “Hello, world!”
...@@ -596,10 +596,55 @@ rollout 100%: ...@@ -596,10 +596,55 @@ rollout 100%:
fi fi
} }
# Extracts variables prefixed with K8S_SECRET_
# and creates a Kubernetes secret.
#
# e.g. If we have the following environment variables:
# K8S_SECRET_A=value1
# K8S_SECRET_B=multi\ word\ value
#
# Then we will create a secret with the following key-value pairs:
# data:
# A: dmFsdWUxCg==
# B: bXVsdGkgd29yZCB2YWx1ZQo=
function create_application_secret() {
track="${1-stable}"
export APPLICATION_SECRET_NAME=$(application_secret_name "$track")
bash -c '
function k8s_prefixed_variables() {
env | sed -n "s/^K8S_SECRET_\(.*\)$/\1/p"
}
kubectl create secret \
-n "$KUBE_NAMESPACE" generic "$APPLICATION_SECRET_NAME" \
--from-env-file <(k8s_prefixed_variables) -o yaml --dry-run |
kubectl replace -n "$KUBE_NAMESPACE" --force -f -
'
}
function deploy_name() {
name="$CI_ENVIRONMENT_SLUG"
track="${1-stable}"
if [[ "$track" != "stable" ]]; then
name="$name-$track"
fi
echo $name
}
function application_secret_name() {
track="${1-stable}"
name=$(deploy_name "$track")
echo "${name}-secret"
}
function deploy() { function deploy() {
track="${1-stable}" track="${1-stable}"
percentage="${2:-100}" percentage="${2:-100}"
name="$CI_ENVIRONMENT_SLUG" name=$(deploy_name "$track")
replicas="1" replicas="1"
service_enabled="true" service_enabled="true"
...@@ -608,7 +653,6 @@ rollout 100%: ...@@ -608,7 +653,6 @@ rollout 100%:
# if track is different than stable, # if track is different than stable,
# re-use all attached resources # re-use all attached resources
if [[ "$track" != "stable" ]]; then if [[ "$track" != "stable" ]]; then
name="$name-$track"
service_enabled="false" service_enabled="false"
postgres_enabled="false" postgres_enabled="false"
fi fi
...@@ -621,6 +665,8 @@ rollout 100%: ...@@ -621,6 +665,8 @@ rollout 100%:
secret_name='' secret_name=''
fi fi
create_application_secret "$track"
if [[ -n "$DB_INITIALIZE" && -z "$(helm ls -q "^$name$")" ]]; then if [[ -n "$DB_INITIALIZE" && -z "$(helm ls -q "^$name$")" ]]; then
echo "Deploying first release with database initialization..." echo "Deploying first release with database initialization..."
helm upgrade --install \ helm upgrade --install \
...@@ -633,6 +679,7 @@ rollout 100%: ...@@ -633,6 +679,7 @@ rollout 100%:
--set image.secrets[0].name="$secret_name" \ --set image.secrets[0].name="$secret_name" \
--set application.track="$track" \ --set application.track="$track" \
--set application.database_url="$DATABASE_URL" \ --set application.database_url="$DATABASE_URL" \
--set application.secretName="$APPLICATION_SECRET_NAME" \
--set service.url="$CI_ENVIRONMENT_URL" \ --set service.url="$CI_ENVIRONMENT_URL" \
--set replicaCount="$replicas" \ --set replicaCount="$replicas" \
--set postgresql.enabled="$postgres_enabled" \ --set postgresql.enabled="$postgres_enabled" \
...@@ -665,6 +712,7 @@ rollout 100%: ...@@ -665,6 +712,7 @@ rollout 100%:
--set image.secrets[0].name="$secret_name" \ --set image.secrets[0].name="$secret_name" \
--set application.track="$track" \ --set application.track="$track" \
--set application.database_url="$DATABASE_URL" \ --set application.database_url="$DATABASE_URL" \
--set application.secretName="$APPLICATION_SECRET_NAME" \
--set service.url="$CI_ENVIRONMENT_URL" \ --set service.url="$CI_ENVIRONMENT_URL" \
--set replicaCount="$replicas" \ --set replicaCount="$replicas" \
--set postgresql.enabled="$postgres_enabled" \ --set postgresql.enabled="$postgres_enabled" \
...@@ -684,11 +732,7 @@ rollout 100%: ...@@ -684,11 +732,7 @@ rollout 100%:
function scale() { function scale() {
track="${1-stable}" track="${1-stable}"
percentage="${2-100}" percentage="${2-100}"
name="$CI_ENVIRONMENT_SLUG" name=$(deploy_name "$track")
if [[ "$track" != "stable" ]]; then
name="$name-$track"
fi
replicas=$(get_replicas "$track" "$percentage") replicas=$(get_replicas "$track" "$percentage")
...@@ -882,15 +926,14 @@ rollout 100%: ...@@ -882,15 +926,14 @@ rollout 100%:
function delete() { function delete() {
track="${1-stable}" track="${1-stable}"
name="$CI_ENVIRONMENT_SLUG" name=$(deploy_name "$track")
if [[ "$track" != "stable" ]]; then
name="$name-$track"
fi
if [[ -n "$(helm ls -q "^$name$")" ]]; then if [[ -n "$(helm ls -q "^$name$")" ]]; then
helm delete --purge "$name" helm delete --purge "$name"
fi fi
secret_name=$(application_secret_name "$track")
kubectl delete secret --ignore-not-found -n "$KUBE_NAMESPACE" "$secret_name"
} }
before_script: before_script:
......
...@@ -9997,6 +9997,9 @@ msgstr "" ...@@ -9997,6 +9997,9 @@ msgstr ""
msgid "You have reached your project limit" msgid "You have reached your project limit"
msgstr "" msgstr ""
msgid "You may also add variables that are made available to the running application by prepending the variable key with <code>K8S_SECRET_</code>."
msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account" msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr "" msgstr ""
......
run lambda { |env| [200, { 'Content-Type' => 'text/plain' }, StringIO.new("Hello World!\n")] } run lambda { |env| [200, { 'Content-Type' => 'text/plain' }, StringIO.new("Hello World! #{ENV['OPTIONAL_MESSAGE']}\n")] }
...@@ -92,6 +92,10 @@ module QA ...@@ -92,6 +92,10 @@ module QA
find_element(name).set(true) find_element(name).set(true)
end end
def uncheck_element(name)
find_element(name).set(false)
end
def click_element(name) def click_element(name)
find_element(name).click find_element(name).click
end end
......
...@@ -33,8 +33,8 @@ module QA ...@@ -33,8 +33,8 @@ module QA
click_on 'Add Kubernetes cluster' click_on 'Add Kubernetes cluster'
end end
def check_rbac! def uncheck_rbac!
check_element :rbac_checkbox uncheck_element :rbac_checkbox
end end
end end
end end
......
...@@ -29,7 +29,7 @@ module QA ...@@ -29,7 +29,7 @@ module QA
page.set_api_url(@cluster.api_url) page.set_api_url(@cluster.api_url)
page.set_ca_certificate(@cluster.ca_certificate) page.set_ca_certificate(@cluster.ca_certificate)
page.set_token(@cluster.token) page.set_token(@cluster.token)
page.check_rbac! if @cluster.rbac page.uncheck_rbac! unless @cluster.rbac
page.add_cluster! page.add_cluster!
end end
......
...@@ -5,17 +5,15 @@ require 'pathname' ...@@ -5,17 +5,15 @@ require 'pathname'
module QA module QA
context 'Configure', :orchestrated, :kubernetes do context 'Configure', :orchestrated, :kubernetes do
describe 'Auto DevOps support' do describe 'Auto DevOps support' do
after do def login
@cluster&.remove!
end
[true, false].each do |rbac|
context "when rbac is #{rbac ? 'enabled' : 'disabled'}" do
it 'user creates a new project and runs auto devops' do
Runtime::Browser.visit(:gitlab, Page::Main::Login) Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials } Page::Main::Login.act { sign_in_using_credentials }
end
project = Resource::Project.fabricate! do |p| before(:all) do
login
@project = Resource::Project.fabricate! do |p|
p.name = Runtime::Env.auto_devops_project_name || 'project-with-autodevops' p.name = Runtime::Env.auto_devops_project_name || 'project-with-autodevops'
p.description = 'Project with Auto Devops' p.description = 'Project with Auto Devops'
end end
...@@ -23,14 +21,14 @@ module QA ...@@ -23,14 +21,14 @@ module QA
# Disable code_quality check in Auto DevOps pipeline as it takes # Disable code_quality check in Auto DevOps pipeline as it takes
# too long and times out the test # too long and times out the test
Resource::CiVariable.fabricate! do |resource| Resource::CiVariable.fabricate! do |resource|
resource.project = project resource.project = @project
resource.key = 'CODE_QUALITY_DISABLED' resource.key = 'CODE_QUALITY_DISABLED'
resource.value = '1' resource.value = '1'
end end
# Create Auto Devops compatible repo # Create Auto Devops compatible repo
Resource::Repository::ProjectPush.fabricate! do |push| Resource::Repository::ProjectPush.fabricate! do |push|
push.project = project push.project = @project
push.directory = Pathname push.directory = Pathname
.new(__dir__) .new(__dir__)
.join('../../../../../fixtures/auto_devops_rack') .join('../../../../../fixtures/auto_devops_rack')
...@@ -38,27 +36,71 @@ module QA ...@@ -38,27 +36,71 @@ module QA
end end
Page::Project::Show.act { wait_for_push } Page::Project::Show.act { wait_for_push }
end
[true, false].each do |rbac|
context "when rbac is #{rbac ? 'enabled' : 'disabled'}" do
before(:all) do
# Create and connect K8s cluster # Create and connect K8s cluster
@cluster = Service::KubernetesCluster.new(rbac: rbac).create! @cluster = Service::KubernetesCluster.new(rbac: rbac).create!
kubernetes_cluster = Resource::KubernetesCluster.fabricate! do |cluster| kubernetes_cluster = Resource::KubernetesCluster.fabricate! do |cluster|
cluster.project = project cluster.project = @project
cluster.cluster = @cluster cluster.cluster = @cluster
cluster.install_helm_tiller = true cluster.install_helm_tiller = true
cluster.install_ingress = true cluster.install_ingress = true
cluster.install_prometheus = true cluster.install_prometheus = true
cluster.install_runner = true cluster.install_runner = true
end end
kubernetes_cluster.populate(:ingress_ip) kubernetes_cluster.populate(:ingress_ip)
project.visit! @project.visit!
Page::Project::Menu.act { click_ci_cd_settings } Page::Project::Menu.act { click_ci_cd_settings }
Page::Project::Settings::CICD.perform do |p| Page::Project::Settings::CICD.perform do |p|
p.enable_auto_devops_with_domain( p.enable_auto_devops_with_domain(
"#{kubernetes_cluster.ingress_ip}.nip.io") "#{kubernetes_cluster.ingress_ip}.nip.io")
end end
end
after(:all) do
@cluster&.remove!
end
before do
login
end
it 'runs auto devops' do
@project.visit!
Page::Project::Menu.act { click_ci_cd_pipelines }
Page::Project::Pipeline::Index.act { go_to_latest_pipeline }
Page::Project::Pipeline::Show.perform do |pipeline|
expect(pipeline).to have_build('build', status: :success, wait: 600)
expect(pipeline).to have_build('test', status: :success, wait: 600)
expect(pipeline).to have_build('production', status: :success, wait: 1200)
end
project.visit! Page::Project::Menu.act { click_operations_environments }
Page::Project::Operations::Environments::Index.perform do |index|
index.go_to_environment('production')
end
Page::Project::Operations::Environments::Show.perform do |show|
show.view_deployment do
expect(page).to have_content('Hello World!')
end
end
end
it 'user sets application secret variable and Auto DevOps passes it to container' do
# Set an application secret CI variable (prefixed with K8S_SECRET_)
Resource::CiVariable.fabricate! do |resource|
resource.project = @project
resource.key = 'K8S_SECRET_OPTIONAL_MESSAGE'
resource.value = 'You can see this application secret'
end
@project.visit!
Page::Project::Menu.act { click_ci_cd_pipelines } Page::Project::Menu.act { click_ci_cd_pipelines }
Page::Project::Pipeline::Index.act { go_to_latest_pipeline } Page::Project::Pipeline::Index.act { go_to_latest_pipeline }
...@@ -69,12 +111,15 @@ module QA ...@@ -69,12 +111,15 @@ module QA
end end
Page::Project::Menu.act { click_operations_environments } Page::Project::Menu.act { click_operations_environments }
Page::Project::Operations::Environments::Index.perform do |index| Page::Project::Operations::Environments::Index.perform do |index|
index.go_to_environment('production') index.go_to_environment('production')
end end
Page::Project::Operations::Environments::Show.perform do |show| Page::Project::Operations::Environments::Show.perform do |show|
show.view_deployment do show.view_deployment do
expect(page).to have_content('Hello World!') expect(page).to have_content('Hello World!')
expect(page).to have_content('You can see this application secret')
end end
end end
end end
......
...@@ -33,32 +33,6 @@ describe 'Gcp Cluster', :js do ...@@ -33,32 +33,6 @@ describe 'Gcp Cluster', :js do
context 'when user filled form with valid parameters' do context 'when user filled form with valid parameters' do
subject { click_button 'Create Kubernetes cluster' } subject { click_button 'Create Kubernetes cluster' }
shared_examples 'valid cluster gcp form' do
it 'users sees a form with the GCP token' do
expect(page).to have_selector(:css, 'form[data-token="token"]')
end
it 'user sees a cluster details page and creation status' do
subject
expect(page).to have_content('Kubernetes cluster is being created on Google Kubernetes Engine...')
Clusters::Cluster.last.provider.make_created!
expect(page).to have_content('Kubernetes cluster was successfully created on Google Kubernetes Engine')
end
it 'user sees a error if something wrong during creation' do
subject
expect(page).to have_content('Kubernetes cluster is being created on Google Kubernetes Engine...')
Clusters::Cluster.last.provider.make_errored!('Something wrong!')
expect(page).to have_content('Something wrong!')
end
end
before do before do
allow_any_instance_of(GoogleApi::CloudPlatform::Client) allow_any_instance_of(GoogleApi::CloudPlatform::Client)
.to receive(:projects_zones_clusters_create) do .to receive(:projects_zones_clusters_create) do
...@@ -82,14 +56,32 @@ describe 'Gcp Cluster', :js do ...@@ -82,14 +56,32 @@ describe 'Gcp Cluster', :js do
fill_in 'cluster[provider_gcp_attributes][machine_type]', with: 'n1-standard-2' fill_in 'cluster[provider_gcp_attributes][machine_type]', with: 'n1-standard-2'
end end
it_behaves_like 'valid cluster gcp form' it 'users sees a form with the GCP token' do
expect(page).to have_selector(:css, 'form[data-token="token"]')
end
context 'RBAC is enabled for the cluster' do it 'user sees a cluster details page and creation status' do
before do subject
check 'cluster_provider_gcp_attributes_legacy_abac'
expect(page).to have_content('Kubernetes cluster is being created on Google Kubernetes Engine...')
Clusters::Cluster.last.provider.make_created!
expect(page).to have_content('Kubernetes cluster was successfully created on Google Kubernetes Engine')
end
it 'user sees a error if something wrong during creation' do
subject
expect(page).to have_content('Kubernetes cluster is being created on Google Kubernetes Engine...')
Clusters::Cluster.last.provider.make_errored!('Something wrong!')
expect(page).to have_content('Something wrong!')
end end
it_behaves_like 'valid cluster gcp form' it 'user sees RBAC is enabled by default' do
expect(page).to have_checked_field('RBAC-enabled cluster')
end end
end end
......
...@@ -23,19 +23,6 @@ describe 'User Cluster', :js do ...@@ -23,19 +23,6 @@ describe 'User Cluster', :js do
end end
context 'when user filled form with valid parameters' do context 'when user filled form with valid parameters' do
shared_examples 'valid cluster user form' do
it 'user sees a cluster details page' do
subject
expect(page).to have_content('Kubernetes cluster integration')
expect(page.find_field('cluster[name]').value).to eq('dev-cluster')
expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value)
.to have_content('http://example.com')
expect(page.find_field('cluster[platform_kubernetes_attributes][token]').value)
.to have_content('my-token')
end
end
before do before do
fill_in 'cluster_name', with: 'dev-cluster' fill_in 'cluster_name', with: 'dev-cluster'
fill_in 'cluster_platform_kubernetes_attributes_api_url', with: 'http://example.com' fill_in 'cluster_platform_kubernetes_attributes_api_url', with: 'http://example.com'
...@@ -44,20 +31,19 @@ describe 'User Cluster', :js do ...@@ -44,20 +31,19 @@ describe 'User Cluster', :js do
subject { click_button 'Add Kubernetes cluster' } subject { click_button 'Add Kubernetes cluster' }
it_behaves_like 'valid cluster user form' it 'user sees a cluster details page' do
context 'RBAC is enabled for the cluster' do
before do
check 'cluster_platform_kubernetes_attributes_authorization_type'
end
it_behaves_like 'valid cluster user form'
it 'user sees a cluster details page with RBAC enabled' do
subject subject
expect(page.find_field('cluster[platform_kubernetes_attributes][authorization_type]', disabled: true)).to be_checked expect(page).to have_content('Kubernetes cluster integration')
expect(page.find_field('cluster[name]').value).to eq('dev-cluster')
expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value)
.to have_content('http://example.com')
expect(page.find_field('cluster[platform_kubernetes_attributes][token]').value)
.to have_content('my-token')
end end
it 'user sees RBAC is enabled by default' do
expect(page).to have_checked_field('RBAC-enabled cluster')
end end
end end
......
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { GlModal } from '@gitlab/ui';
import GlModalVuex from '~/vue_shared/components/gl_modal_vuex.vue';
import createState from '~/vuex_shared/modules/modal/state';
const localVue = createLocalVue();
localVue.use(Vuex);
const TEST_SLOT = 'Lorem ipsum modal dolar sit.';
const TEST_MODAL_ID = 'my-modal-id';
const TEST_MODULE = 'myModal';
describe('GlModalVuex', () => {
let wrapper;
let state;
let actions;
const factory = (options = {}) => {
const store = new Vuex.Store({
modules: {
[TEST_MODULE]: {
namespaced: true,
state,
actions,
},
},
});
const propsData = {
modalId: TEST_MODAL_ID,
modalModule: TEST_MODULE,
...options.propsData,
};
wrapper = shallowMount(localVue.extend(GlModalVuex), {
...options,
localVue,
store,
propsData,
});
};
beforeEach(() => {
state = createState();
actions = {
show: jasmine.createSpy('show'),
hide: jasmine.createSpy('hide'),
};
});
it('renders gl-modal', () => {
factory({
slots: {
default: `<div>${TEST_SLOT}</div>`,
},
});
const glModal = wrapper.find(GlModal);
expect(glModal.props('modalId')).toBe(TEST_MODAL_ID);
expect(glModal.text()).toContain(TEST_SLOT);
});
it('passes props through to gl-modal', () => {
const title = 'Test Title';
const okVariant = 'success';
factory({
propsData: {
title,
okTitle: title,
okVariant,
},
});
const glModal = wrapper.find(GlModal);
expect(glModal.attributes('title')).toEqual(title);
expect(glModal.attributes('oktitle')).toEqual(title);
expect(glModal.attributes('okvariant')).toEqual(okVariant);
});
it('passes listeners through to gl-modal', () => {
const ok = jasmine.createSpy('ok');
factory({
listeners: { ok },
});
const glModal = wrapper.find(GlModal);
glModal.vm.$emit('ok');
expect(ok).toHaveBeenCalledTimes(1);
});
it('calls vuex action on show', () => {
expect(actions.show).not.toHaveBeenCalled();
factory();
const glModal = wrapper.find(GlModal);
glModal.vm.$emit('shown');
expect(actions.show).toHaveBeenCalledTimes(1);
});
it('calls vuex action on hide', () => {
expect(actions.hide).not.toHaveBeenCalled();
factory();
const glModal = wrapper.find(GlModal);
glModal.vm.$emit('hidden');
expect(actions.hide).toHaveBeenCalledTimes(1);
});
it('calls bootstrap show when isVisible changes', done => {
state.isVisible = false;
factory();
const rootEmit = spyOn(wrapper.vm.$root, '$emit');
state.isVisible = true;
localVue
.nextTick()
.then(() => {
expect(rootEmit).toHaveBeenCalledWith('bv::show::modal', TEST_MODAL_ID);
})
.then(done)
.catch(done.fail);
});
it('calls bootstrap hide when isVisible changes', done => {
state.isVisible = true;
factory();
const rootEmit = spyOn(wrapper.vm.$root, '$emit');
state.isVisible = false;
localVue
.nextTick()
.then(() => {
expect(rootEmit).toHaveBeenCalledWith('bv::hide::modal', TEST_MODAL_ID);
})
.then(done)
.catch(done.fail);
});
});
import * as types from '~/vuex_shared/modules/modal/mutation_types';
import * as actions from '~/vuex_shared/modules/modal/actions';
import testAction from 'spec/helpers/vuex_action_helper';
describe('Vuex ModalModule actions', () => {
describe('open', () => {
it('works', done => {
const data = { id: 7 };
testAction(actions.open, data, {}, [{ type: types.OPEN, payload: data }], [], done);
});
});
describe('close', () => {
it('works', done => {
testAction(actions.close, null, {}, [{ type: types.CLOSE }], [], done);
});
});
describe('show', () => {
it('works', done => {
testAction(actions.show, null, {}, [{ type: types.SHOW }], [], done);
});
});
describe('hide', () => {
it('works', done => {
testAction(actions.hide, null, {}, [{ type: types.HIDE }], [], done);
});
});
});
import mutations from '~/vuex_shared/modules/modal/mutations';
import * as types from '~/vuex_shared/modules/modal/mutation_types';
describe('Vuex ModalModule mutations', () => {
describe(types.SHOW, () => {
it('sets isVisible to true', () => {
const state = {
isVisible: false,
};
mutations[types.SHOW](state);
expect(state).toEqual({
isVisible: true,
});
});
});
describe(types.HIDE, () => {
it('sets isVisible to false', () => {
const state = {
isVisible: true,
};
mutations[types.HIDE](state);
expect(state).toEqual({
isVisible: false,
});
});
});
describe(types.OPEN, () => {
it('sets data and sets isVisible to true', () => {
const data = { id: 7 };
const state = {
isVisible: false,
data: null,
};
mutations[types.OPEN](state, data);
expect(state).toEqual({
isVisible: true,
data,
});
});
});
});
...@@ -29,7 +29,7 @@ describe Clusters::Applications::CertManager do ...@@ -29,7 +29,7 @@ describe Clusters::Applications::CertManager do
expect(subject.name).to eq('certmanager') expect(subject.name).to eq('certmanager')
expect(subject.chart).to eq('stable/cert-manager') expect(subject.chart).to eq('stable/cert-manager')
expect(subject.version).to eq('v0.5.2') expect(subject.version).to eq('v0.5.2')
expect(subject).not_to be_rbac expect(subject).to be_rbac
expect(subject.files).to eq(cert_manager.files.merge(cluster_issuer_file)) expect(subject.files).to eq(cert_manager.files.merge(cluster_issuer_file))
expect(subject.postinstall).to eq(['/usr/bin/kubectl create -f /data/helm/certmanager/config/cluster_issuer.yaml']) expect(subject.postinstall).to eq(['/usr/bin/kubectl create -f /data/helm/certmanager/config/cluster_issuer.yaml'])
end end
...@@ -45,12 +45,12 @@ describe Clusters::Applications::CertManager do ...@@ -45,12 +45,12 @@ describe Clusters::Applications::CertManager do
end end
end end
context 'on a rbac enabled cluster' do context 'on a non rbac enabled cluster' do
before do before do
cert_manager.cluster.platform_kubernetes.rbac! cert_manager.cluster.platform_kubernetes.abac!
end end
it { is_expected.to be_rbac } it { is_expected.not_to be_rbac }
end end
context 'application failed to install previously' do context 'application failed to install previously' do
......
...@@ -49,16 +49,16 @@ describe Clusters::Applications::Helm do ...@@ -49,16 +49,16 @@ describe Clusters::Applications::Helm do
end end
describe 'rbac' do describe 'rbac' do
context 'non rbac cluster' do context 'rbac cluster' do
it { expect(subject).not_to be_rbac } it { expect(subject).to be_rbac }
end end
context 'rbac cluster' do context 'non rbac cluster' do
before do before do
helm.cluster.platform_kubernetes.rbac! helm.cluster.platform_kubernetes.abac!
end end
it { expect(subject).to be_rbac } it { expect(subject).not_to be_rbac }
end end
end end
end end
......
...@@ -91,16 +91,16 @@ describe Clusters::Applications::Ingress do ...@@ -91,16 +91,16 @@ describe Clusters::Applications::Ingress do
expect(subject.name).to eq('ingress') expect(subject.name).to eq('ingress')
expect(subject.chart).to eq('stable/nginx-ingress') expect(subject.chart).to eq('stable/nginx-ingress')
expect(subject.version).to eq('0.23.0') expect(subject.version).to eq('0.23.0')
expect(subject).not_to be_rbac expect(subject).to be_rbac
expect(subject.files).to eq(ingress.files) expect(subject.files).to eq(ingress.files)
end end
context 'on a rbac enabled cluster' do context 'on a non rbac enabled cluster' do
before do before do
ingress.cluster.platform_kubernetes.rbac! ingress.cluster.platform_kubernetes.abac!
end end
it { is_expected.to be_rbac } it { is_expected.not_to be_rbac }
end end
context 'application failed to install previously' do context 'application failed to install previously' do
......
...@@ -52,17 +52,17 @@ describe Clusters::Applications::Jupyter do ...@@ -52,17 +52,17 @@ describe Clusters::Applications::Jupyter do
expect(subject.name).to eq('jupyter') expect(subject.name).to eq('jupyter')
expect(subject.chart).to eq('jupyter/jupyterhub') expect(subject.chart).to eq('jupyter/jupyterhub')
expect(subject.version).to eq('v0.6') expect(subject.version).to eq('v0.6')
expect(subject).not_to be_rbac expect(subject).to be_rbac
expect(subject.repository).to eq('https://jupyterhub.github.io/helm-chart/') expect(subject.repository).to eq('https://jupyterhub.github.io/helm-chart/')
expect(subject.files).to eq(jupyter.files) expect(subject.files).to eq(jupyter.files)
end end
context 'on a rbac enabled cluster' do context 'on a non rbac enabled cluster' do
before do before do
jupyter.cluster.platform_kubernetes.rbac! jupyter.cluster.platform_kubernetes.abac!
end end
it { is_expected.to be_rbac } it { is_expected.not_to be_rbac }
end end
context 'application failed to install previously' do context 'application failed to install previously' do
......
...@@ -161,20 +161,16 @@ describe Clusters::Applications::Prometheus do ...@@ -161,20 +161,16 @@ describe Clusters::Applications::Prometheus do
expect(subject.name).to eq('prometheus') expect(subject.name).to eq('prometheus')
expect(subject.chart).to eq('stable/prometheus') expect(subject.chart).to eq('stable/prometheus')
expect(subject.version).to eq('6.7.3') expect(subject.version).to eq('6.7.3')
expect(subject).not_to be_rbac expect(subject).to be_rbac
expect(subject.files).to eq(prometheus.files) expect(subject.files).to eq(prometheus.files)
end end
it 'should not install knative metrics' do context 'on a non rbac enabled cluster' do
expect(subject.postinstall).to be_nil
end
context 'on a rbac enabled cluster' do
before do before do
prometheus.cluster.platform_kubernetes.rbac! prometheus.cluster.platform_kubernetes.abac!
end end
it { is_expected.to be_rbac } it { is_expected.not_to be_rbac }
end end
context 'application failed to install previously' do context 'application failed to install previously' do
...@@ -185,13 +181,17 @@ describe Clusters::Applications::Prometheus do ...@@ -185,13 +181,17 @@ describe Clusters::Applications::Prometheus do
end end
end end
it 'should not install knative metrics' do
expect(subject.postinstall).to be_nil
end
context 'with knative installed' do context 'with knative installed' do
let(:knative) { create(:clusters_applications_knative, :installed ) } let(:knative) { create(:clusters_applications_knative, :installed ) }
let(:prometheus) { create(:clusters_applications_prometheus, cluster: knative.cluster) } let(:prometheus) { create(:clusters_applications_prometheus, cluster: knative.cluster) }
subject { prometheus.install_command } subject { prometheus.install_command }
it 'should install metrics' do it 'should install knative metrics' do
expect(subject.postinstall).to include("kubectl apply -f #{Clusters::Applications::Knative::METRICS_CONFIG}") expect(subject.postinstall).to include("kubectl apply -f #{Clusters::Applications::Knative::METRICS_CONFIG}")
end end
end end
......
...@@ -47,17 +47,17 @@ describe Clusters::Applications::Runner do ...@@ -47,17 +47,17 @@ describe Clusters::Applications::Runner do
expect(subject.name).to eq('runner') expect(subject.name).to eq('runner')
expect(subject.chart).to eq('runner/gitlab-runner') expect(subject.chart).to eq('runner/gitlab-runner')
expect(subject.version).to eq('0.1.43') expect(subject.version).to eq('0.1.43')
expect(subject).not_to be_rbac expect(subject).to be_rbac
expect(subject.repository).to eq('https://charts.gitlab.io') expect(subject.repository).to eq('https://charts.gitlab.io')
expect(subject.files).to eq(gitlab_runner.files) expect(subject.files).to eq(gitlab_runner.files)
end end
context 'on a rbac enabled cluster' do context 'on a non rbac enabled cluster' do
before do before do
gitlab_runner.cluster.platform_kubernetes.rbac! gitlab_runner.cluster.platform_kubernetes.abac!
end end
it { is_expected.to be_rbac } it { is_expected.not_to be_rbac }
end end
context 'application failed to install previously' do context 'application failed to install previously' do
......
...@@ -154,21 +154,13 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching ...@@ -154,21 +154,13 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
end end
describe '#rbac?' do describe '#rbac?' do
subject { kubernetes.rbac? }
let(:kubernetes) { build(:cluster_platform_kubernetes, :configured) } let(:kubernetes) { build(:cluster_platform_kubernetes, :configured) }
context 'when authorization type is rbac' do subject { kubernetes.rbac? }
let(:kubernetes) { build(:cluster_platform_kubernetes, :rbac_enabled, :configured) }
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
end end
context 'when authorization type is nil' do
it { is_expected.to be_falsey }
end
end
describe '#actual_namespace' do describe '#actual_namespace' do
let(:cluster) { create(:cluster, :project) } let(:cluster) { create(:cluster, :project) }
let(:project) { cluster.project } let(:project) { cluster.project }
......
...@@ -79,17 +79,7 @@ describe Clusters::Providers::Gcp do ...@@ -79,17 +79,7 @@ describe Clusters::Providers::Gcp do
subject { gcp } subject { gcp }
it 'should default to true' do it { is_expected.not_to be_legacy_abac }
is_expected.to be_legacy_abac
end
context 'legacy_abac is set to false' do
let(:gcp) { build(:cluster_provider_gcp, legacy_abac: false) }
it 'is false' do
is_expected.not_to be_legacy_abac
end
end
end end
describe '#state_machine' do describe '#state_machine' do
......
...@@ -3244,6 +3244,24 @@ describe Project do ...@@ -3244,6 +3244,24 @@ describe Project do
end end
end end
describe '#update' do
let(:project) { create(:project) }
it 'validates the visibility' do
expect(project).to receive(:visibility_level_allowed_as_fork).and_call_original
expect(project).to receive(:visibility_level_allowed_by_group).and_call_original
project.update(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
end
it 'does not validate the visibility' do
expect(project).not_to receive(:visibility_level_allowed_as_fork).and_call_original
expect(project).not_to receive(:visibility_level_allowed_by_group).and_call_original
project.update(updated_at: Time.now)
end
end
describe '#last_repository_updated_at' do describe '#last_repository_updated_at' do
it 'sets to created_at upon creation' do it 'sets to created_at upon creation' do
project = create(:project, created_at: 2.hours.ago) project = create(:project, created_at: 2.hours.ago)
...@@ -3470,6 +3488,13 @@ describe Project do ...@@ -3470,6 +3488,13 @@ describe Project do
expect { project.migrate_to_hashed_storage! }.to change { project.repository_read_only }.to(true) expect { project.migrate_to_hashed_storage! }.to change { project.repository_read_only }.to(true)
end end
it 'does not validate project visibility' do
expect(project).not_to receive(:visibility_level_allowed_as_fork)
expect(project).not_to receive(:visibility_level_allowed_by_group)
project.migrate_to_hashed_storage!
end
it 'schedules ProjectMigrateHashedStorageWorker with delayed start when the project repo is in use' do it 'schedules ProjectMigrateHashedStorageWorker with delayed start when the project repo is in use' do
Gitlab::ReferenceCounter.new(project.gl_repository(is_wiki: false)).increase Gitlab::ReferenceCounter.new(project.gl_repository(is_wiki: false)).increase
......
...@@ -27,6 +27,8 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService, '#execute' d ...@@ -27,6 +27,8 @@ describe Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService, '#execute' d
stub_kubeclient_get_secret_error(api_url, 'gitlab-token') stub_kubeclient_get_secret_error(api_url, 'gitlab-token')
stub_kubeclient_create_secret(api_url) stub_kubeclient_create_secret(api_url)
stub_kubeclient_get_role_binding(api_url, "gitlab-#{namespace}", namespace: namespace)
stub_kubeclient_put_role_binding(api_url, "gitlab-#{namespace}", namespace: namespace)
stub_kubeclient_get_namespace(api_url, namespace: namespace) stub_kubeclient_get_namespace(api_url, namespace: namespace)
stub_kubeclient_get_service_account_error(api_url, "#{namespace}-service-account", namespace: namespace) stub_kubeclient_get_service_account_error(api_url, "#{namespace}-service-account", namespace: namespace)
stub_kubeclient_create_service_account(api_url, namespace: namespace) stub_kubeclient_create_service_account(api_url, namespace: namespace)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment