Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Collect uptime data in daily heartbeat from connect-ng #1069

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions app/controllers/api/connect/v3/systems/systems_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@ class Api::Connect::V3::Systems::SystemsController < Api::Connect::BaseControlle
before_action :authenticate_system

def update
if params[:online_at].present?
params[:online_at].each do |online_at|
dthours = online_at.split(':')
chajain marked this conversation as resolved.
Show resolved Hide resolved
if dthours.count == 2
begin
@system_uptime = SystemUptime.create!(system_id: @system.id, online_at_day: dthours[0], online_at_hours: dthours[1])
logger.debug(N_("Added uptime information for system '%s'") % @system.id)
rescue ActiveRecord::RecordNotUnique
logger.debug(N_("Uptime information existing for system '%s'") % @system.id)
end
else
logger.error(N_("Uptime data is malformed '%s'") % online_at)
end
end
end

@system.hostname = params[:hostname]

# Since the payload is handled by rails all values are converted to string
Expand Down
1 change: 1 addition & 0 deletions app/models/system.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class System < ApplicationRecord
has_many :services, through: :activations
has_many :repositories, -> { distinct }, through: :services
has_many :products, -> { distinct }, through: :services
has_many :system_uptimes, dependent: :destroy

validates :system_token, uniqueness: { scope: %i[login password], case_sensitive: false }

Expand Down
7 changes: 7 additions & 0 deletions app/models/system_uptime.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class SystemUptime < ApplicationRecord
belongs_to :system

validates :system_id, presence: true
validates :online_at_day, presence: true
validates :online_at_hours, presence: true
end
18 changes: 18 additions & 0 deletions db/migrate/20240111200053_create_system_uptimes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class CreateSystemUptimes < ActiveRecord::Migration[6.1]
def change
felixsch marked this conversation as resolved.
Show resolved Hide resolved
safety_assured do
create_table :system_uptimes, id: :serial, force: :cascade do |t|
t.bigint :system_id, null: false
t.date :online_at_day, null: false
t.column :online_at_hours, 'binary(24)', null: false
t.timestamps
end

commit_db_transaction

add_index :system_uptimes, %i[system_id online_at_day], unique: true, name: 'id_online_day'

add_foreign_key :system_uptimes, :systems, column: :system_id, validate: false
end
end
end
294 changes: 152 additions & 142 deletions db/schema.rb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/rmt.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module RMT
VERSION ||= '2.15'.freeze
VERSION ||= '2.16'.freeze

DEFAULT_USER = '_rmt'.freeze
DEFAULT_GROUP = 'nginx'.freeze
Expand Down
16 changes: 16 additions & 0 deletions lib/suse/connect/system_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class SUSE::Connect::SystemSerializer < ActiveModel::Serializer
attribute :hostname, if: :needs_full_update?
attribute :hwinfo, if: :has_hwinfo_and_needs_full_update?
attribute :products, if: :needs_full_update?
attribute :systemuptimes, if: :has_systemuptime?

# We send the internal system id as system_token if the system (in RMT) is
# duplicated (therefore using the system_token mechanism).
Expand Down Expand Up @@ -47,6 +48,17 @@ def products
end
end

def systemuptimes
object.system_uptimes.map do |systemuptime|
payload = {
system_id: systemuptime.system_id,
online_at_day: systemuptime.online_at_day,
online_at_hours: systemuptime.online_at_hours
}
payload
end
end

def hwinfo
JSON.parse(object.system_information).symbolize_keys
end
Expand All @@ -59,6 +71,10 @@ def has_system_token?
object.system_token.present?
end

def has_systemuptime?
systemuptimes.any?
end

def needs_full_update?
!object.scc_synced_at
end
Expand Down
8 changes: 8 additions & 0 deletions lib/tasks/system_uptimes.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace :db do
namespace :maintenance do
desc 'Delete all uptime tracking data which are older than 90 days'
task cleanup_uptime_tracking: :environment do
SystemUptime.where("online_at_day < '#{2.days.ago}'").delete_all
end
end
end
12 changes: 12 additions & 0 deletions package/files/systemd/rmt-uptime-cleanup.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[Unit]
Description=RMT uptime cleanup service
Requires=mysql.service
Wants=rmt-uptime-cleanup.timer

[Service]
Type=oneshot
WorkingDirectory=/usr/share/rmt/bin
ExecStart=bundle exec rake db:maintenance:cleanup_uptime_tracking RAILS_ENV=production

[Install]
WantedBy=multi-user.target
10 changes: 10 additions & 0 deletions package/files/systemd/rmt-uptime-cleanup.timer
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Unit]
Description=RMT Uptime Data cleanup timer

[Timer]
# Run this timer every day at a randomized 24h delay.
OnCalendar=daily
RandomizedDelaySec=24h

[Install]
WantedBy=timers.target
18 changes: 12 additions & 6 deletions package/obs/rmt-server.spec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#
# spec file for package rmt-server
#
# Copyright (c) 2023 SUSE LLC
# Copyright (c) 2024 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
Expand Down Expand Up @@ -30,7 +30,7 @@
%define ruby_version %{rb_default_ruby_suffix}

Name: rmt-server
Version: 2.15
Version: 2.16
Release: 0
Summary: Repository mirroring tool and registration proxy for SCC
License: GPL-2.0-or-later
Expand Down Expand Up @@ -145,13 +145,15 @@ mkdir -p %{buildroot}%{_unitdir}
install -m 444 package/files/systemd/rmt-server-mirror.timer %{buildroot}%{_unitdir}
install -m 444 package/files/systemd/rmt-server-sync.timer %{buildroot}%{_unitdir}
install -m 444 package/files/systemd/rmt-server-systems-scc-sync.timer %{buildroot}%{_unitdir}
install -m 444 package/files/systemd/rmt-uptime-cleanup.timer %{buildroot}%{_unitdir}

install -m 444 package/files/systemd/rmt-server-mirror.service %{buildroot}%{_unitdir}
install -m 444 package/files/systemd/rmt-server-sync.service %{buildroot}%{_unitdir}
install -m 444 package/files/systemd/rmt-server-systems-scc-sync.service %{buildroot}%{_unitdir}
install -m 444 package/files/systemd/rmt-server.service %{buildroot}%{_unitdir}
install -m 444 package/files/systemd/rmt-server.target %{buildroot}%{_unitdir}
install -m 444 package/files/systemd/rmt-server-migration.service %{buildroot}%{_unitdir}
install -m 444 package/files/systemd/rmt-uptime-cleanup.service %{buildroot}%{_unitdir}

install -m 444 engines/registration_sharing/package/rmt-server-regsharing.service %{buildroot}%{_unitdir}
install -m 444 engines/registration_sharing/package/rmt-server-regsharing.timer %{buildroot}%{_unitdir}
Expand All @@ -164,6 +166,7 @@ ln -fs %{_sbindir}/service %{buildroot}%{_sbindir}/rcrmt-server-migration
ln -fs %{_sbindir}/service %{buildroot}%{_sbindir}/rcrmt-server-mirror
ln -fs %{_sbindir}/service %{buildroot}%{_sbindir}/rcrmt-server-sync
ln -fs %{_sbindir}/service %{buildroot}%{_sbindir}/rcrmt-server-systems-scc-sync
ln -fs %{_sbindir}/service %{buildroot}%{_sbindir}/rcrmt-uptime-cleanup

ln -fs %{_sbindir}/service %{buildroot}%{_sbindir}/rcrmt-server-regsharing
ln -fs %{_sbindir}/service %{buildroot}%{_sbindir}/rcrmt-server-trim-cache
Expand Down Expand Up @@ -270,6 +273,7 @@ chrpath -d %{buildroot}%{lib_dir}/vendor/bundle/ruby/*/extensions/*/*/mysql2-*/m
%{_sbindir}/rcrmt-server-sync
%{_sbindir}/rcrmt-server-mirror
%{_sbindir}/rcrmt-server-systems-scc-sync
%{_sbindir}/rcrmt-uptime-cleanup
%{_unitdir}/rmt-server.target
%{_unitdir}/rmt-server.service
%{_unitdir}/rmt-server-migration.service
Expand All @@ -279,6 +283,8 @@ chrpath -d %{buildroot}%{lib_dir}/vendor/bundle/ruby/*/extensions/*/*/mysql2-*/m
%{_unitdir}/rmt-server-sync.timer
%{_unitdir}/rmt-server-systems-scc-sync.service
%{_unitdir}/rmt-server-systems-scc-sync.timer
%{_unitdir}/rmt-uptime-cleanup.service
%{_unitdir}/rmt-uptime-cleanup.timer
%dir %{_datadir}/bash-completion/
%dir %{_datadir}/bash-completion/completions/
%{_datadir}/bash-completion/completions/rmt-cli
Expand Down Expand Up @@ -319,10 +325,10 @@ getent group %{rmt_group} >/dev/null || %{_sbindir}/groupadd -r %{rmt_group}
getent passwd %{rmt_user} >/dev/null || \
%{_sbindir}/useradd -g %{rmt_group} -s /bin/false -r \
-c "user for RMT" %{rmt_user}
%service_add_pre rmt-server.target rmt-server.service rmt-server-migration.service rmt-server-mirror.service rmt-server-sync.service rmt-server-systems-scc-sync.service
%service_add_pre rmt-server.target rmt-server.service rmt-server-migration.service rmt-server-mirror.service rmt-server-sync.service rmt-server-systems-scc-sync.service rmt-uptime-cleanup.service

%post
%service_add_post rmt-server.target rmt-server.service rmt-server-migration.service rmt-server-mirror.service rmt-server-sync.service rmt-server-systems-scc-sync.service
%service_add_post rmt-server.target rmt-server.service rmt-server-migration.service rmt-server-mirror.service rmt-server-sync.service rmt-server-systems-scc-sync.service rmt-uptime-cleanup.service

# Run only on install
if [ $1 -eq 1 ]; then
Expand Down Expand Up @@ -355,10 +361,10 @@ if [ ! -e %{_datadir}/rmt/public/suma ]; then
fi

%preun
%service_del_preun rmt-server.target rmt-server.service rmt-server-migration.service rmt-server-mirror.service rmt-server-sync.service rmt-server-systems-scc-sync.service
%service_del_preun rmt-server.target rmt-server.service rmt-server-migration.service rmt-server-mirror.service rmt-server-sync.service rmt-server-systems-scc-sync.service rmt-uptime-cleanup.service

%postun
%service_del_postun rmt-server.target rmt-server.service rmt-server-migration.service rmt-server-mirror.service rmt-server-sync.service rmt-server-systems-scc-sync.service
%service_del_postun rmt-server.target rmt-server.service rmt-server-migration.service rmt-server-mirror.service rmt-server-sync.service rmt-server-systems-scc-sync.service rmt-uptime-cleanup.service

%posttrans config
# Don't fail if either systemd or nginx are not running
Expand Down
7 changes: 7 additions & 0 deletions spec/factories/system_uptimes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FactoryBot.define do
factory :system_uptime do
association :system
sequence(:online_at_day) { Time.zone.now }
online_at_hours { '111111111111111111111111' }
end
end
6 changes: 6 additions & 0 deletions spec/factories/systems.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,11 @@
trait :with_system_token do
sequence(:system_token) { |n| "00000000-0000-4000-9000-#{n.to_s.rjust(12, '0')}" }
end

trait :with_system_uptimes do
after :create do |system, _|
create(:system_uptime, system: system)
end
end
end
end
9 changes: 9 additions & 0 deletions spec/lib/suse/connect/system_serializer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,13 @@
expect(serializer.key? :system_token).to eq(false)
end
end

context 'system with systemuptime' do
let(:system) { create :system, :with_system_uptimes }

it 'match systemuptime data' do
expect((serializer[:systemuptimes][0][:online_at_day]).to_date).to eq(Time.zone.now.to_date)
expect((serializer[:systemuptimes][0][:online_at_hours]).to_s).to eq('111111111111111111111111')
end
end
end
7 changes: 7 additions & 0 deletions spec/models/system_uptime_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require 'rails_helper'

RSpec.describe SystemUptime, type: :model do
it { is_expected.to validate_presence_of(:system_id) }
it { is_expected.to validate_presence_of(:online_at_day) }
it { is_expected.to validate_presence_of(:online_at_hours) }
end
37 changes: 37 additions & 0 deletions spec/requests/api/connect/v3/systems/systems_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
}
end
let(:payload) { { hostname: 'test', hwinfo: hwinfo } }
let(:systemuptime) { system.system_uptimes.first }
let(:online_hours) { ':111111111111111111111111' }

describe '#update' do
subject(:update_action) { put url, params: payload, headers: headers }
Expand Down Expand Up @@ -45,6 +47,41 @@
expect(information[:cpus]).to eq('16')
end
end

context 'when uptime data provided' do
let(:payload) { { hostname: 'test', hwinfo: hwinfo, online_at: [1.day.ago.to_date.to_s << online_hours] } }

it 'inserts the uptime data in system_uptimes table' do
update_action

expect(systemuptime.system_id).to eq(system.reload.id)
expect(systemuptime.online_at_day.to_date).to eq(1.day.ago.to_date)
expect(systemuptime.online_at_hours.to_s).to eq('111111111111111111111111')
end
end

context 'when same uptime data added twice' do
let(:payload) { { hostname: 'test', hwinfo: hwinfo, online_at: [1.day.ago.to_date.to_s << online_hours, 1.day.ago.to_date.to_s << online_hours] } }

it 'avoids duplication if multiple records have same data' do
update_action

expect(system.system_uptimes.count).to eq(1)
expect(systemuptime.system_id).to eq(system.reload.id)
expect(systemuptime.online_at_day.to_date).to eq(1.day.ago.to_date)
expect(systemuptime.online_at_hours.to_s).to eq('111111111111111111111111')
end
end

context 'when uptime data is malformed' do
let(:payload) { { hostname: 'test', hwinfo: hwinfo, online_at: [1.day.ago.to_date.to_s] } }

it 'record is not inserted' do
update_action

expect(system.system_uptimes.count).to eq(0)
end
end
end

context 'when hostname is not provided' do
Expand Down
Loading