Commit 54e7f53a authored by Rémy Coutable's avatar Rémy Coutable

Merge branch '788-geo-nodes-removal' into 'master'

Geo: Enables nodes to be removed even without proper license

Closes #788

See merge request !978
parents 95f28ff2 61f04311
class Admin::GeoNodesController < Admin::ApplicationController
before_action :check_license
before_action :check_license, except: [:index, :destroy]
before_action :load_node, only: [:destroy, :repair, :backfill_repositories]
def index
@nodes = GeoNode.all
@node = GeoNode.new
unless Gitlab::Geo.license_allows?
flash.now[:alert] = 'You need a different license to enable Geo replication'
end
end
def create
......
= form_for geo_node, as: :geo_node, url: admin_geo_nodes_path, html: { class: 'form-horizontal' } do |f|
-if geo_node.errors.any?
.alert.alert-danger
- geo_node.errors.full_messages.each do |msg|
%p= msg
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :primary do
= f.check_box :primary
%strong This is a primary node
.form-group
= f.label :url, 'URL', class: 'control-label'
.col-sm-10
= f.text_field :url, class: 'form-control'
= f.fields_for :geo_node_key, geo_node.geo_node_key do |fg|
.form-group
= fg.label :key, 'Public Key', class: 'control-label'
.col-sm-10
= fg.text_area :key, class: 'form-control thin_area', rows: 5
%p.help-block
Paste a machine public key here for the GitLab user this node runs on. Read more about how to generate it
= link_to "here", help_page_path("ssh/README")
.form-actions
= f.submit 'Add Node', class: 'btn btn-create'
%hr
......@@ -8,34 +8,7 @@
%hr
= form_for @node, as: :geo_node, url: admin_geo_nodes_path, html: { class: 'form-horizontal' } do |f|
-if @node.errors.any?
.alert.alert-danger
- @node.errors.full_messages.each do |msg|
%p= msg
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :primary do
= f.check_box :primary
%strong This is a primary node
.form-group
= f.label :url, 'URL', class: 'control-label'
.col-sm-10
= f.text_field :url, class: 'form-control'
= f.fields_for :geo_node_key, @node.geo_node_key do |fg|
.form-group
= fg.label :key, 'Public Key', class: 'control-label'
.col-sm-10
= fg.text_area :key, class: 'form-control thin_area', rows: 5
%p.help-block
Paste a machine public key here for the GitLab user this node runs on. Read more about how to generate it
= link_to "here", help_page_path("ssh/README")
.form-actions
= f.submit 'Add Node', class: 'btn btn-create'
%hr
= render :partial => 'form', locals: {geo_node: @node} if Gitlab::Geo.license_allows?
-if @nodes.any?
.panel.panel-default
......@@ -52,14 +25,15 @@
%span.help-block #{node.primary ? 'Primary node' : 'Secondary node'}
.pull-right
- if node.missing_oauth_application?
= link_to repair_admin_geo_node_path(node), method: :post, title: 'OAuth application is missing', class: 'btn btn-default btn-sm prepend-left-10' do
= icon('exclamation-triangle fw')
Repair authentication
- unless node.primary?
= link_to backfill_repositories_admin_geo_node_path(node), method: :post, class: 'btn btn-primary btn-sm prepend-left-10' do
= icon 'map-signs'
Backfill all repositories
- if Gitlab::Geo.license_allows?
- if node.missing_oauth_application?
= link_to repair_admin_geo_node_path(node), method: :post, title: 'OAuth application is missing', class: 'btn btn-default btn-sm prepend-left-10' do
= icon('exclamation-triangle fw')
Repair authentication
- unless node.primary?
= link_to backfill_repositories_admin_geo_node_path(node), method: :post, class: 'btn btn-primary btn-sm prepend-left-10' do
= icon 'map-signs'
Backfill all repositories
= link_to admin_geo_node_path(node), data: { confirm: 'Are you sure?' }, method: :delete, class: 'btn btn-remove btn-sm prepend-left-10' do
= icon 'trash'
Remove
---
title: 'Geo: Enables nodes to be removed even without proper license'
merge_request: 978
author:
require 'spec_helper'
describe Admin::GeoNodesController do
shared_examples 'unlicensed geo action' do
it 'redirects to the license page' do
expect(response).to redirect_to(admin_license_path)
end
it 'displays a flash message' do
expect(controller).to set_flash[:alert].to('You need a different license to enable Geo replication')
end
end
let(:user) { create(:user) }
let(:admin) { create(:admin) }
before do
sign_in(admin)
end
describe '#index' do
render_views
subject { get :index }
context 'with add-on license available' do
before do
allow(Gitlab::Geo).to receive(:license_allows?).and_return(true)
end
it 'renders creation form' do
expect(subject).to render_template(partial: 'admin/geo_nodes/_form')
end
end
context 'without add-on license available' do
before do
allow(Gitlab::Geo).to receive(:license_allows?).and_return(false)
end
it 'does not render the creation form' do
expect(subject).not_to render_template(partial: 'admin/geo_nodes/_form')
end
it 'displays a flash message' do
subject
expect(controller).to set_flash.now[:alert].to('You need a different license to enable Geo replication')
end
it 'does not redirects to the license page' do
subject
expect(response).not_to redirect_to(admin_license_path)
end
end
end
describe '#destroy' do
let!(:geo_node) { create(:geo_node) }
subject do
delete(:destroy, id: geo_node)
end
context 'without add-on license' do
before do
allow(Gitlab::Geo).to receive(:license_allows?).and_return(false)
end
it 'deletes the node' do
expect { subject }.to change { GeoNode.count }.by(-1)
end
end
context 'with add-on license' do
before do
allow(Gitlab::Geo).to receive(:license_allows?).and_return(true)
end
it 'deletes the node' do
expect { subject }.to change { GeoNode.count }.by(-1)
end
end
end
describe '#create' do
let(:geo_node_attributes) { { url: 'http://example.com', geo_node_key_attributes: { key: SSHKeygen.generate } } }
subject { post :create, geo_node: geo_node_attributes }
context 'without add-on license' do
before do
allow(Gitlab::Geo).to receive(:license_allows?) { false }
subject
end
it_behaves_like 'unlicensed geo action'
end
context 'with add-on license' do
before do
allow(Gitlab::Geo).to receive(:license_allows?).and_return(true)
end
it 'creates the node' do
expect { subject }.to change { GeoNode.count }.by(1)
end
end
end
describe '#repair' do
let(:geo_node) { create(:geo_node) }
subject { post :repair, id: geo_node }
before do
allow(Gitlab::Geo).to receive(:license_allows?) { false }
subject
end
it_behaves_like 'unlicensed geo action'
end
describe '#backfill_repositories' do
let(:geo_node) { create(:geo_node) }
subject { post :backfill_repositories, id: geo_node }
before do
allow(Gitlab::Geo).to receive(:license_allows?) { false }
subject
end
it_behaves_like 'unlicensed geo action'
end
end
......@@ -2,13 +2,7 @@ FactoryGirl.define do
factory :geo_node_key, class: 'GeoNodeKey' do
title
key do
"ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0= dummy@gitlab.com"
end
trait :another_key do
key do
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDmTillFzNTrrGgwaCKaSj+QCz81E6jBc/s9av0+3b1Hwfxgkqjl4nAK/OD2NjgyrONDTDfR8cRN4eAAy6nY8GLkOyYBDyuc5nTMqs5z3yVuTwf3koGm/YQQCmo91psZ2BgDFTor8SVEE5Mm1D1k3JDMhDFxzzrOtRYFPci9lskTJaBjpqWZ4E9rDTD2q/QZntCqbC3wE9uSemRQB5f8kik7vD/AD8VQXuzKladrZKkzkONCPWsXDspUitjM8HkQdOf0PsYn1CMUC1xKYbCxkg5TkEosIwGv6CoEArUrdu/4+10LVslq494mAvEItywzrluCLCnwELfW+h/m8UHoVhZ"
end
SSHKeygen.generate
end
end
end
......@@ -7,7 +7,6 @@ FactoryGirl.define do
trait :primary do
primary true
port { Gitlab.config.gitlab.port }
association :geo_node_key, :another_key
end
end
end
require 'openssl'
require 'base64'
#
# Copyright:: Copyright (c) 2015 Chris Marchesi
# Copyright:: Copyright (c) 2016 GitLab Inc
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
class SSHKeygen
class << self
def generate
"ssh-rsa #{openssh_rsa_public_key(generate_private_key)}"
end
private
def generate_private_key
::OpenSSL::PKey::RSA.new(2048)
end
# Encode an OpenSSH RSA public key.
# Key format is PEM-encoded - size (big-endian), then data:
# * Type (ie: len: 7 (size of string), data: ssh-rsa)
# * Exponent (len/data)
# * Modulus (len+1/NUL+data)
def openssh_rsa_public_key(private_key)
enc_type = "#{[7].pack('N')}ssh-rsa"
enc_exponent = "#{[private_key.public_key.e.num_bytes].pack('N')}#{private_key.public_key.e.to_s(2)}"
enc_modulus = "#{[private_key.public_key.n.num_bytes + 1].pack('N')}\0#{private_key.public_key.n.to_s(2)}"
Base64.strict_encode64("#{enc_type}#{enc_exponent}#{enc_modulus}")
end
end
end
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