Commit c4fb85c0 authored by Nick Thomas's avatar Nick Thomas

Merge branch '3230-add-geo-project-created-events' into 'master'

Geo - Log a repository created event when a project is created

See merge request !2807
parents 8382156c f3eacf88
......@@ -2,6 +2,10 @@ module Geo
class EventLog < ActiveRecord::Base
include Geo::Model
belongs_to :repository_created_event,
class_name: 'Geo::RepositoryCreatedEvent',
foreign_key: :repository_created_event_id
belongs_to :repository_updated_event,
class_name: 'Geo::RepositoryUpdatedEvent',
foreign_key: :repository_updated_event_id
......@@ -19,7 +23,8 @@ module Geo
foreign_key: :repositories_changed_event_id
def event
repository_updated_event ||
repository_created_event ||
repository_updated_event ||
repository_deleted_event ||
repository_renamed_event ||
repositories_changed_event
......
module Geo
class RepositoryCreatedEvent < ActiveRecord::Base
include Geo::Model
belongs_to :project
validates :project, :project_name, :repo_path, :repository_storage_name,
:repository_storage_path, presence: true
end
end
module Geo
class RepositoryCreatedEventStore < EventStore
self.event_type = :repository_created_event
private
def build_event
Geo::RepositoryCreatedEvent.new(
project: project,
repository_storage_name: project.repository.storage,
repository_storage_path: project.repository_storage_path,
repo_path: project.disk_path,
wiki_path: "#{project.disk_path}.wiki",
project_name: project.name
)
end
end
end
---
title: Geo - Log a repository created event when a project is created
merge_request: 2807
author:
type: added
class CreateGeoRepositoryCreatedEvents < ActiveRecord::Migration
DOWNTIME = false
def change
create_table :geo_repository_created_events, id: :bigserial do |t|
t.references :project, index: true, foreign_key: { on_delete: :cascade }, null: false
t.text :repository_storage_name, null: false
t.text :repository_storage_path, null: false
t.text :repo_path, null: false
t.text :wiki_path
t.text :project_name, null: false
end
add_column :geo_event_log, :repository_created_event_id, :integer, limit: 8
end
end
class AddIndexToGeoEventLogRepositoryCreatedEventId < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :geo_event_log, :repository_created_event_id
end
def down
if index_exists? :geo_event_log, :repository_created_event_id
remove_concurrent_index :geo_event_log, :repository_created_event_id
end
end
end
class AddGeoRepositoryCreatedEventsFkOnGeoEventLog < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_foreign_key :geo_event_log, :geo_repository_created_events,
column: :repository_created_event_id, on_delete: :cascade
end
def down
remove_foreign_key :geo_event_log, column: :repository_created_event_id
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170905202320) do
ActiveRecord::Schema.define(version: 20170906160132) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -669,9 +669,11 @@ ActiveRecord::Schema.define(version: 20170905202320) do
t.integer "repository_deleted_event_id", limit: 8
t.integer "repository_renamed_event_id", limit: 8
t.integer "repositories_changed_event_id", limit: 8
t.integer "repository_created_event_id", limit: 8
end
add_index "geo_event_log", ["repositories_changed_event_id"], name: "index_geo_event_log_on_repositories_changed_event_id", using: :btree
add_index "geo_event_log", ["repository_created_event_id"], name: "index_geo_event_log_on_repository_created_event_id", using: :btree
add_index "geo_event_log", ["repository_deleted_event_id"], name: "index_geo_event_log_on_repository_deleted_event_id", using: :btree
add_index "geo_event_log", ["repository_renamed_event_id"], name: "index_geo_event_log_on_repository_renamed_event_id", using: :btree
add_index "geo_event_log", ["repository_updated_event_id"], name: "index_geo_event_log_on_repository_updated_event_id", using: :btree
......@@ -711,6 +713,17 @@ ActiveRecord::Schema.define(version: 20170905202320) do
add_index "geo_repositories_changed_events", ["geo_node_id"], name: "index_geo_repositories_changed_events_on_geo_node_id", using: :btree
create_table "geo_repository_created_events", id: :bigserial, force: :cascade do |t|
t.integer "project_id", null: false
t.text "repository_storage_name", null: false
t.text "repository_storage_path", null: false
t.text "repo_path", null: false
t.text "wiki_path"
t.text "project_name", null: false
end
add_index "geo_repository_created_events", ["project_id"], name: "index_geo_repository_created_events_on_project_id", using: :btree
create_table "geo_repository_deleted_events", id: :bigserial, force: :cascade do |t|
t.integer "project_id", null: false
t.text "repository_storage_name", null: false
......@@ -2057,12 +2070,14 @@ ActiveRecord::Schema.define(version: 20170905202320) do
add_foreign_key "events_for_migration", "users", column: "author_id", name: "fk_edfd187b6f", on_delete: :cascade
add_foreign_key "forked_project_links", "projects", column: "forked_to_project_id", name: "fk_434510edb0", on_delete: :cascade
add_foreign_key "geo_event_log", "geo_repositories_changed_events", column: "repositories_changed_event_id", name: "fk_4a99ebfd60", on_delete: :cascade
add_foreign_key "geo_event_log", "geo_repository_created_events", column: "repository_created_event_id", name: "fk_9b9afb1916", on_delete: :cascade
add_foreign_key "geo_event_log", "geo_repository_deleted_events", column: "repository_deleted_event_id", name: "fk_c4b1c1f66e", on_delete: :cascade
add_foreign_key "geo_event_log", "geo_repository_renamed_events", column: "repository_renamed_event_id", name: "fk_86c84214ec", on_delete: :cascade
add_foreign_key "geo_event_log", "geo_repository_updated_events", column: "repository_updated_event_id", on_delete: :cascade
add_foreign_key "geo_node_namespace_links", "geo_nodes", on_delete: :cascade
add_foreign_key "geo_node_namespace_links", "namespaces", on_delete: :cascade
add_foreign_key "geo_repositories_changed_events", "geo_nodes", on_delete: :cascade
add_foreign_key "geo_repository_created_events", "projects", on_delete: :cascade
add_foreign_key "geo_repository_renamed_events", "projects", on_delete: :cascade
add_foreign_key "geo_repository_updated_events", "projects", on_delete: :cascade
add_foreign_key "index_statuses", "projects", name: "fk_74b2492545", on_delete: :cascade
......
......@@ -9,7 +9,7 @@ module EE
mirror_user_id = params.delete(:mirror_user_id)
mirror_trigger_builds = params.delete(:mirror_trigger_builds)
super do |project|
project = super do |project|
# Repository size limit comes as MB from the view
project.repository_size_limit = ::Gitlab::Utils.try_megabytes_to_bytes(limit) if limit
......@@ -19,10 +19,18 @@ module EE
project.mirror_user_id = mirror_user_id
end
end
log_geo_event(project) if project&.persisted?
project
end
private
def log_geo_event(project)
::Geo::RepositoryCreatedEventStore.new(project).create
end
def after_create_actions
raise NotImplementedError unless defined?(super)
......
......@@ -66,6 +66,8 @@ module Gitlab
if event_log.repository_updated_event
handle_repository_update(event_log)
elsif event_log.repository_created_event
handle_repository_created(event_log)
elsif event_log.repository_deleted_event
handle_repository_delete(event_log)
elsif event_log.repositories_changed_event
......@@ -104,6 +106,24 @@ module Gitlab
Gitlab::Geo.current_node&.projects_include?(event_log.project_id)
end
def handle_repository_created(event_log)
created_event = event_log.repository_created_event
registry = ::Geo::ProjectRegistry.find_or_initialize_by(project_id: created_event.project_id)
registry.resync_repository = true
registry.resync_wiki = created_event.wiki_path.present?
log_event_info(
event_log.created_at,
message: 'Repository created',
project_id: created_event.project_id,
repo_path: created_event.repo_path,
wiki_path: created_event.wiki_path,
resync_repository: registry.resync_repository,
resync_wiki: registry.resync_wiki)
registry.save!
end
def handle_repository_update(event)
updated_event = event.repository_updated_event
registry = ::Geo::ProjectRegistry.find_or_initialize_by(project_id: updated_event.project_id)
......
......@@ -134,7 +134,24 @@ describe Projects::CreateService, '#execute' do
end
end
context 'when running on a primary node' do
let!(:geo_node) { create(:geo_node, :primary, :current) }
it 'logs an event to the Geo event log' do
expect { create_project(user, opts) }.to change(Geo::RepositoryCreatedEvent, :count).by(1)
end
it 'does not log event to the Geo log if project creation fails' do
failing_opts = {
name: nil,
namespace: user.namespace
}
expect { create_project(user, failing_opts) }.not_to change(Geo::RepositoryCreatedEvent, :count)
end
end
def create_project(user, opts)
Projects::CreateService.new(user, opts).execute
described_class.new(user, opts).execute
end
end
FactoryGirl.define do
factory :geo_event_log, class: Geo::EventLog do
trait :created_event do
repository_created_event factory: :geo_repository_created_event
end
trait :updated_event do
repository_updated_event factory: :geo_repository_updated_event
end
......@@ -13,11 +17,22 @@ FactoryGirl.define do
end
end
factory :geo_repository_created_event, class: Geo::RepositoryCreatedEvent do
project
repository_storage_name { project.repository_storage }
repository_storage_path { project.repository_storage_path }
add_attribute(:repo_path) { project.disk_path }
project_name { project.name }
wiki_path { "{project.disk_path}.wiki" }
end
factory :geo_repository_updated_event, class: Geo::RepositoryUpdatedEvent do
project
source 0
branches_affected 0
tags_affected 0
project
end
factory :geo_repository_deleted_event, class: Geo::RepositoryDeletedEvent do
......
......@@ -23,6 +23,38 @@ describe Gitlab::Geo::LogCursor::Daemon, :postgresql do
end
end
context 'when replaying a repository created event' do
let(:repository_created_event) { create(:geo_repository_created_event) }
let(:event_log) { create(:geo_event_log, repository_created_event: repository_created_event) }
let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) }
before do
allow(subject).to receive(:exit?).and_return(false, true)
end
it 'creates a new project registry' do
expect { subject.run! }.to change(Geo::ProjectRegistry, :count).by(1)
end
it 'sets resync attributes to true' do
subject.run!
registry = Geo::ProjectRegistry.last
expect(registry).to have_attributes(resync_repository: true, resync_wiki: true)
end
it 'sets resync_wiki to false if wiki_path is nil' do
repository_created_event.update_attribute(:wiki_path, nil)
subject.run!
registry = Geo::ProjectRegistry.last
expect(registry).to have_attributes(resync_repository: true, resync_wiki: false)
end
end
context 'when replaying a repository updated event' do
let(:event_log) { create(:geo_event_log, :updated_event) }
let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) }
......
......@@ -2,10 +2,11 @@ require 'spec_helper'
RSpec.describe Geo::EventLog, type: :model do
describe 'relationships' do
it { is_expected.to belong_to(:repository_updated_event).class_name('Geo::RepositoryUpdatedEvent').with_foreign_key('repository_updated_event_id') }
it { is_expected.to belong_to(:repositories_changed_event).class_name('Geo::RepositoriesChangedEvent').with_foreign_key('repositories_changed_event_id') }
it { is_expected.to belong_to(:repository_created_event).class_name('Geo::RepositoryCreatedEvent').with_foreign_key('repository_created_event_id') }
it { is_expected.to belong_to(:repository_deleted_event).class_name('Geo::RepositoryDeletedEvent').with_foreign_key('repository_deleted_event_id') }
it { is_expected.to belong_to(:repository_renamed_event).class_name('Geo::RepositoryRenamedEvent').with_foreign_key('repository_renamed_event_id') }
it { is_expected.to belong_to(:repositories_changed_event).class_name('Geo::RepositoriesChangedEvent').with_foreign_key('repositories_changed_event_id') }
it { is_expected.to belong_to(:repository_updated_event).class_name('Geo::RepositoryUpdatedEvent').with_foreign_key('repository_updated_event_id') }
end
describe '#event' do
......@@ -13,6 +14,13 @@ RSpec.describe Geo::EventLog, type: :model do
expect(subject.event).to be_nil
end
it 'returns repository_created_event when set' do
repository_created_event = build(:geo_repository_created_event)
subject.repository_created_event = repository_created_event
expect(subject.event).to eq repository_created_event
end
it 'returns repository_updated_event when set' do
repository_updated_event = build(:geo_repository_updated_event)
subject.repository_updated_event = repository_updated_event
......
require 'spec_helper'
describe Geo::RepositoryCreatedEvent, type: :model do
describe 'relationships' do
it { is_expected.to belong_to(:project) }
end
describe 'validations' do
it { is_expected.to validate_presence_of(:project) }
it { is_expected.to validate_presence_of(:project_name) }
it { is_expected.to validate_presence_of(:repo_path) }
it { is_expected.to validate_presence_of(:repository_storage_name) }
it { is_expected.to validate_presence_of(:repository_storage_path) }
end
end
require 'spec_helper'
describe Geo::RepositoryCreatedEventStore do
let(:project) { create(:project) }
subject(:event) { described_class.new(project) }
describe '#create' do
it 'does not create an event when not running on a primary node' do
allow(Gitlab::Geo).to receive(:primary?) { false }
expect { event.create }.not_to change(Geo::RepositoryCreatedEvent, :count)
end
context 'when running on a primary node' do
before do
allow(Gitlab::Geo).to receive(:primary?) { true }
end
it 'creates a created event' do
expect { event.create }.to change(Geo::RepositoryCreatedEvent, :count).by(1)
end
it 'tracks information for the created project' do
event.create
event = Geo::RepositoryCreatedEvent.last
expect(event).to have_attributes(
project_id: project.id,
repo_path: project.disk_path,
wiki_path: "#{project.disk_path}.wiki",
project_name: project.name,
repository_storage_name: project.repository_storage,
repository_storage_path: project.repository_storage_path
)
end
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