Commit 8d0ed73b authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 6a6caaf360ab
......@@ -6,7 +6,7 @@ const newClusterViews = [':clusters:new', ':clusters:create_gcp', ':clusters:cre
const isProjectLevelCluster = page => page.startsWith('project:clusters');
export default (document, gon) => {
export default document => {
const { page } = document.body.dataset;
const isNewClusterView = newClusterViews.some(view => page.endsWith(view));
......@@ -19,17 +19,15 @@ export default (document, gon) => {
initGkeDropdowns();
if (gon.features.createEksClusters) {
import(/* webpackChunkName: 'eks_cluster' */ '~/create_cluster/eks_cluster')
.then(({ default: initCreateEKSCluster }) => {
const el = document.querySelector('.js-create-eks-cluster-form-container');
import(/* webpackChunkName: 'eks_cluster' */ '~/create_cluster/eks_cluster')
.then(({ default: initCreateEKSCluster }) => {
const el = document.querySelector('.js-create-eks-cluster-form-container');
if (el) {
initCreateEKSCluster(el);
}
})
.catch(() => {});
}
if (el) {
initCreateEKSCluster(el);
}
})
.catch(() => {});
if (isProjectLevelCluster(page)) {
initGkeNamespace();
......
......@@ -12,9 +12,6 @@ class Clusters::ClustersController < Clusters::BaseController
before_action :authorize_update_cluster!, only: [:update]
before_action :authorize_admin_cluster!, only: [:destroy, :clear_cache]
before_action :update_applications_status, only: [:cluster_status]
before_action only: [:new, :create_gcp] do
push_frontend_feature_flag(:create_eks_clusters)
end
before_action only: [:show] do
push_frontend_feature_flag(:enable_cluster_application_elastic_stack)
push_frontend_feature_flag(:enable_cluster_application_crossplane)
......@@ -42,8 +39,6 @@ def index
end
def new
return unless Feature.enabled?(:create_eks_clusters)
if params[:provider] == 'aws'
@aws_role = current_user.aws_role || Aws::Role.new
@aws_role.ensure_role_external_id!
......@@ -113,6 +108,7 @@ def create_gcp
generate_gcp_authorize_url
validate_gcp_token
user_cluster
params[:provider] = 'gcp'
render :new, locals: { active_tab: 'create' }
end
......@@ -277,8 +273,7 @@ def create_role_params
end
def generate_gcp_authorize_url
params = Feature.enabled?(:create_eks_clusters) ? { provider: :gke } : {}
state = generate_session_key_redirect(clusterable.new_path(params).to_s)
state = generate_session_key_redirect(clusterable.new_path(provider: :gcp).to_s)
@authorize_url = GoogleApi::CloudPlatform::Client.new(
nil, callback_google_api_auth_url,
......
......@@ -26,13 +26,13 @@ def execute(container_repository)
def delete_tags(tags_to_delete, tags_by_digest)
deleted_digests = group_by_digest(tags_to_delete).select do |digest, tags|
delete_tag_digest(digest, tags, tags_by_digest[digest])
delete_tag_digest(tags, tags_by_digest[digest])
end
deleted_digests.values.flatten
end
def delete_tag_digest(digest, tags, other_tags)
def delete_tag_digest(tags, other_tags)
# Issue: https://gitlab.com/gitlab-org/gitlab-foss/issues/21405
# we have to remove all tags due
# to Docker Distribution bug unable
......
......@@ -24,32 +24,36 @@ def smart_delete(container_repository, tag_names)
dummy_manifest = container_repository.client.generate_empty_manifest(container_repository.path)
return error('could not generate manifest') if dummy_manifest.nil?
# update the manifests of the tags with the new dummy image
deleted_tags = []
tag_digests = []
deleted_tags = replace_tag_manifests(container_repository, dummy_manifest, tag_names)
# Deletes the dummy image
# All created tag digests are the same since they all have the same dummy image.
# a single delete is sufficient to remove all tags with it
if deleted_tags.any? && container_repository.delete_tag_by_digest(deleted_tags.values.first)
success(deleted: deleted_tags.keys)
else
error('could not delete tags')
end
end
# update the manifests of the tags with the new dummy image
def replace_tag_manifests(container_repository, dummy_manifest, tag_names)
deleted_tags = {}
tag_names.each do |name|
digest = container_repository.client.put_tag(container_repository.path, name, dummy_manifest)
next unless digest
deleted_tags << name
tag_digests << digest
deleted_tags[name] = digest
end
# make sure the digests are the same (it should always be)
tag_digests.uniq!
digests = deleted_tags.values.uniq
# rubocop: disable CodeReuse/ActiveRecord
Gitlab::Sentry.track_exception(ArgumentError.new('multiple tag digests')) if tag_digests.many?
Gitlab::Sentry.track_exception(ArgumentError.new('multiple tag digests')) if digests.many?
# Deletes the dummy image
# All created tag digests are the same since they all have the same dummy image.
# a single delete is sufficient to remove all tags with it
if tag_digests.any? && container_repository.delete_tag_by_digest(tag_digests.first)
success(deleted: deleted_tags)
else
error('could not delete tags')
end
deleted_tags
end
end
end
......
......@@ -8,5 +8,5 @@
= render_if_exists 'admin/application_settings/slack'
= render 'admin/application_settings/third_party_offers'
= render 'admin/application_settings/snowplow'
= render 'admin/application_settings/eks' if Feature.enabled?(:create_eks_clusters)
= render 'admin/application_settings/eks'
= render 'clusters/clusters/gcp/header'
- if @valid_gcp_token
= render 'clusters/clusters/gcp/form'
- elsif @authorize_url
= render 'clusters/clusters/gcp/signin_with_google_button'
- else
= render 'clusters/clusters/gcp/gcp_not_configured'
.signin-with-google
- create_account_link = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: 'https://accounts.google.com/SignUpWithoutGmail?service=cloudconsole&continue=https%3A%2F%2Fconsole.cloud.google.com%2Ffreetrial%3Futm_campaign%3D2018_cpanel%26utm_source%3Dgitlab%26utm_medium%3Dreferral' }
= link_to(image_tag('auth_buttons/signin_with_google.png', width: '191px', alt: _('Sign in with Google')), @authorize_url)
= s_('or %{link_start}create a new Google account%{link_end}').html_safe % { link_start: create_account_link, link_end: '</a>'.html_safe }
- breadcrumb_title _('Kubernetes')
- page_title _('Kubernetes Cluster')
- create_eks_enabled = Feature.enabled?(:create_eks_clusters)
- active_tab = local_assigns.fetch(:active_tab, 'create')
= javascript_include_tag 'https://apis.google.com/js/api.js'
......@@ -14,21 +13,14 @@
%li.nav-item{ role: 'presentation' }
%a.nav-link{ href: '#create-cluster-pane', id: 'create-cluster-tab', class: active_when(active_tab == 'create'), data: { toggle: 'tab' }, role: 'tab' }
%span
- if create_eks_enabled
= create_new_cluster_label(provider: params[:provider])
- else
= create_new_cluster_label(provider: 'gcp')
= create_new_cluster_label(provider: params[:provider])
%li.nav-item{ role: 'presentation' }
%a.nav-link{ href: '#add-cluster-pane', id: 'add-cluster-tab', class: active_when(active_tab == 'add'), data: { toggle: 'tab' }, role: 'tab' }
%span Add existing cluster
.tab-content.gitlab-tab-content
- if create_eks_enabled
.tab-pane{ id: 'create-cluster-pane', class: active_when(active_tab == 'create'), role: 'tabpanel' }
= render new_cluster_partial(provider: params[:provider])
- else
.tab-pane{ id: 'create-cluster-pane', class: active_when(active_tab == 'create'), role: 'tabpanel' }
= render new_cluster_partial(provider: 'gcp')
.tab-pane{ id: 'create-cluster-pane', class: active_when(active_tab == 'create'), role: 'tabpanel' }
= render new_cluster_partial(provider: params[:provider])
.tab-pane{ id: 'add-cluster-pane', class: active_when(active_tab == 'add'), role: 'tabpanel' }
= render 'clusters/clusters/user/header'
......
---
title: Enable creating Amazon EKS clusters from GitLab
merge_request: 20333
author:
type: added
......@@ -211,33 +211,9 @@ GitLab supports:
Before creating your first cluster on Amazon EKS with GitLab's integration,
make sure the following requirements are met:
- Self-managed GitLab instances have the `create_eks_clusters` feature flag enabled.
- An [Amazon Web Services](https://aws.amazon.com/) account is set up and you are able to log in.
- You have permissions to manage IAM resources.
##### Enable the `create_eks_clusters` feature flag **(CORE ONLY)**
Self-managed instances must have the feature flag `create_eks_clusters` enabled to create
EKS clusters. To enable EKS cluster creation, ask a GitLab administrator with Rails console access
to run the following command:
```ruby
Feature.enable(:create_eks_clusters)
```
To have it enabled for a specific project only, ask a GitLab administrator to run the following
command using a Rails console:
```ruby
Feature.enable(:create_eks_clusters, Project.find_by_full_path('my_group/my_project'))
```
To have this feature disabled, ask a GitLab administrator to run the following command:
```ruby
Feature.disable(:create_eks_clusters)
```
##### Additional requirements for self-managed instances
If you are using a self-managed GitLab instance, GitLab must first
......
......@@ -15948,9 +15948,6 @@ msgstr ""
msgid "Sign in via 2FA code"
msgstr ""
msgid "Sign in with Google"
msgstr ""
msgid "Sign in with Single Sign-On"
msgstr ""
......@@ -21263,9 +21260,6 @@ msgstr ""
msgid "opened %{timeAgoString} by %{user}"
msgstr ""
msgid "or %{link_start}create a new Google account%{link_end}"
msgstr ""
msgid "out of %d total test"
msgid_plural "out of %d total tests"
msgstr[0] ""
......
......@@ -84,29 +84,11 @@ def get_new(provider: 'gcp')
GoogleApi::CloudPlatform::Client.session_key_for_redirect_uri(key)
end
before do
stub_feature_flags(create_eks_clusters: false)
allow(SecureRandom).to receive(:hex).and_return(key)
end
it 'has authorize_url' do
get_new
expect(assigns(:authorize_url)).to include(key)
expect(session[session_key_for_redirect_uri]).to eq(new_admin_cluster_path)
end
context 'when create_eks_clusters feature flag is enabled' do
before do
stub_feature_flags(create_eks_clusters: true)
end
context 'when selected provider is gke and no valid gcp token exists' do
it 'redirects to gcp authorize_url' do
get_new
context 'when selected provider is gke and no valid gcp token exists' do
it 'redirects to gcp authorize_url' do
get_new
expect(response).to redirect_to(assigns(:authorize_url))
end
expect(response).to redirect_to(assigns(:authorize_url))
end
end
end
......
......@@ -97,29 +97,15 @@ def go(provider: 'gcp')
end
before do
stub_feature_flags(create_eks_clusters: false)
allow(SecureRandom).to receive(:hex).and_return(key)
end
it 'has authorize_url' do
it 'redirects to gcp authorize_url' do
go
expect(assigns(:authorize_url)).to include(key)
expect(session[session_key_for_redirect_uri]).to eq(new_group_cluster_path(group))
end
context 'when create_eks_clusters feature flag is enabled' do
before do
stub_feature_flags(create_eks_clusters: true)
end
context 'when selected provider is gke and no valid gcp token exists' do
it 'redirects to gcp authorize_url' do
go
expect(response).to redirect_to(assigns(:authorize_url))
end
end
expect(session[session_key_for_redirect_uri]).to eq(new_group_cluster_path(group, provider: :gcp))
expect(response).to redirect_to(assigns(:authorize_url))
end
end
......
......@@ -95,29 +95,15 @@ def go(provider: 'gcp')
end
before do
stub_feature_flags(create_eks_clusters: false)
allow(SecureRandom).to receive(:hex).and_return(key)
end
it 'has authorize_url' do
it 'redirects to gcp authorize_url' do
go
expect(assigns(:authorize_url)).to include(key)
expect(session[session_key_for_redirect_uri]).to eq(new_project_cluster_path(project))
end
context 'when create_eks_clusters feature flag is enabled' do
before do
stub_feature_flags(create_eks_clusters: true)
end
context 'when selected provider is gke and no valid gcp token exists' do
it 'redirects to gcp authorize_url' do
go
expect(response).to redirect_to(assigns(:authorize_url))
end
end
expect(session[session_key_for_redirect_uri]).to eq(new_project_cluster_path(project, provider: :gcp))
expect(response).to redirect_to(assigns(:authorize_url))
end
end
......
......@@ -18,8 +18,6 @@
let(:project_id) { 'test-project-1234' }
before do
stub_feature_flags(create_eks_clusters: false)
allow_any_instance_of(Projects::ClustersController)
.to receive(:token_in_session).and_return('token')
allow_any_instance_of(Projects::ClustersController)
......@@ -31,7 +29,8 @@
visit project_clusters_path(project)
click_link 'Add Kubernetes cluster'
click_link 'Create new Cluster on GKE'
click_link 'Create new Cluster'
click_link 'Google GKE'
end
context 'when user filled form with valid parameters' do
......@@ -147,21 +146,6 @@
end
end
context 'when user has not signed with Google' do
before do
stub_feature_flags(create_eks_clusters: false)
visit project_clusters_path(project)
click_link 'Add Kubernetes cluster'
click_link 'Create new Cluster on GKE'
end
it 'user sees a login page' do
expect(page).to have_css('.signin-with-google')
expect(page).to have_link('Google account')
end
end
context 'when a user cannot edit the environment scope' do
before do
visit project_clusters_path(project)
......@@ -177,7 +161,6 @@
context 'when user has not dismissed GCP signup offer' do
before do
stub_feature_flags(create_eks_clusters: false)
visit project_clusters_path(project)
end
......@@ -190,18 +173,10 @@
expect(page).to have_css('.gcp-signup-offer')
end
it 'user sees offer on cluster GCP login page' do
click_link 'Add Kubernetes cluster'
click_link 'Create new Cluster on GKE'
expect(page).to have_css('.gcp-signup-offer')
end
end
context 'when user has dismissed GCP signup offer' do
before do
stub_feature_flags(create_eks_clusters: false)
visit project_clusters_path(project)
end
......
......@@ -49,41 +49,20 @@
end
end
context 'when user has not signed in Google' do
context 'user visits create cluster page' do
before do
stub_feature_flags(create_eks_clusters: false)
visit project_clusters_path(project)
click_link 'Add Kubernetes cluster'
click_link 'Create new Cluster on GKE'
click_link 'Create new Cluster'
end
it 'user sees a login page' do
expect(page).to have_css('.signin-with-google')
expect(page).to have_link('Google account')
it 'user sees a link to create a GKE cluster' do
expect(page).to have_link('Google GKE')
end
end
context 'when create_eks_clusters feature flag is enabled' do
before do
stub_feature_flags(create_eks_clusters: true)
end
context 'when user access create cluster page' do
before do
visit project_clusters_path(project)
click_link 'Add Kubernetes cluster'
click_link 'Create new Cluster'
end
it 'user sees a link to create a GKE cluster' do
expect(page).to have_link('Google GKE')
end
it 'user sees a link to create an EKS cluster' do
expect(page).to have_link('Amazon EKS')
end
it 'user sees a link to create an EKS cluster' do
expect(page).to have_link('Amazon EKS')
end
end
end
......@@ -4,15 +4,14 @@ import diffModule from '~/diffs/store/modules';
import SettingsDropdown from '~/diffs/components/settings_dropdown.vue';
import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('Diff settiings dropdown component', () => {
let vm;
let actions;
function createComponent(extendStore = () => {}) {
const localVue = createLocalVue();
localVue.use(Vuex);
const store = new Vuex.Store({
modules: {
diffs: {
......@@ -26,9 +25,10 @@ describe('Diff settiings dropdown component', () => {
extendStore(store);
vm = mount(SettingsDropdown, {
vm = mount(localVue.extend(SettingsDropdown), {
localVue,
store,
sync: false,
});
}
......
import Vue from 'vue';
import frequentItemsListItemComponent from '~/frequent_items/components/frequent_items_list_item.vue';
import { shallowMount } from '@vue/test-utils';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import { trimText } from 'spec/helpers/text_helper';
import { mockProject } from '../mock_data'; // can also use 'mockGroup', but not useful to test here
const createComponent = () => {
const Component = Vue.extend(frequentItemsListItemComponent);
return shallowMount(Component, {
propsData: {
itemId: mockProject.id,
itemName: mockProject.name,
namespace: mockProject.namespace,
webUrl: mockProject.webUrl,
avatarUrl: mockProject.avatarUrl,
},
});
};
const localVue = createLocalVue();
describe('FrequentItemsListItemComponent', () => {
let wrapper;
let vm;
beforeEach(() => {
wrapper = createComponent();
({ vm } = wrapper);
});
const createComponent = (props = {}) => {
wrapper = shallowMount(localVue.extend(frequentItemsListItemComponent), {
propsData: {
itemId: mockProject.id,
itemName: mockProject.name,
namespace: mockProject.namespace,
webUrl: mockProject.webUrl,
avatarUrl: mockProject.avatarUrl,
...props,
},
sync: false,
localVue,
});
};
afterEach(() => {
vm.$destroy();
wrapper.destroy();
wrapper = null;
});
describe('computed', () => {
describe('hasAvatar', () => {
it('should return `true` or `false` if whether avatar is present or not', () => {
wrapper.setProps({ avatarUrl: 'path/to/avatar.png' });
createComponent({ avatarUrl: 'path/to/avatar.png' });
expect(vm.hasAvatar).toBe(true);
expect(wrapper.vm.hasAvatar).toBe(true);
});
wrapper.setProps({ avatarUrl: null });
it('should return `false` if avatar is not present', () => {
createComponent({ avatarUrl: null });
expect(vm.hasAvatar).toBe(false);
expect(wrapper.vm.hasAvatar).toBe(false);
});
});
describe('highlightedItemName', () => {
it('should enclose part of project name in <b> & </b> which matches with `matcher` prop', () => {
wrapper.setProps({ matcher: 'lab' });
createComponent({ matcher: 'lab' });
expect(wrapper.find('.js-frequent-items-item-title').html()).toContain(
'<b>L</b><b>a</b><b>b</b>',
......@@ -55,7 +53,7 @@ describe('FrequentItemsListItemComponent', () => {
});
it('should return project name as it is if `matcher` is not available', () => {
wrapper.setProps({ matcher: null });
createComponent({ matcher: null });
expect(trimText(wrapper.find('.js-frequent-items-item-title').text())).toBe(