Dns manager daemon and clients can be built, once again.
This commit is contained in:
		
							parent
							
								
									ee7d20cc21
								
							
						
					
					
						commit
						a78eb8c889
					
				
					 8 changed files with 80 additions and 42 deletions
				
			
		| 
						 | 
				
			
			@ -22,9 +22,9 @@ dependencies:
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
targets:
 | 
			
		||||
  dnsmanager:
 | 
			
		||||
  dnsmanagerd:
 | 
			
		||||
    main: src/main.cr
 | 
			
		||||
  dnsmanager-client:
 | 
			
		||||
    main: src/client/main.cr
 | 
			
		||||
 | 
			
		||||
license: MIT
 | 
			
		||||
license: ISC
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,15 @@
 | 
			
		|||
require "../../requests/*"
 | 
			
		||||
 | 
			
		||||
class DNSManager::Client < IPC::Client
 | 
			
		||||
class DNSManager::Client < IPC
 | 
			
		||||
	property server_fd : Int32 = -1
 | 
			
		||||
 | 
			
		||||
	def initialize
 | 
			
		||||
		initialize "dnsmanager"
 | 
			
		||||
		super()
 | 
			
		||||
		fd = self.connect "dnsmanager"
 | 
			
		||||
		if fd.nil?
 | 
			
		||||
			raise "couldn't connect to 'auth' IPC service"
 | 
			
		||||
		end
 | 
			
		||||
		@server_fd = fd
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	# TODO: parse_message should raise exception if response not anticipated
 | 
			
		||||
| 
						 | 
				
			
			@ -14,33 +21,50 @@ class DNSManager::Client < IPC::Client
 | 
			
		|||
		em << DNSManager::Response::Error
 | 
			
		||||
		em.parse_ipc_json message
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
	#
 | 
			
		||||
	# Simple users.
 | 
			
		||||
	#
 | 
			
		||||
 | 
			
		||||
# Simple users.
 | 
			
		||||
class DNSManager::Client < IPC::Client
 | 
			
		||||
	def login(token : String)
 | 
			
		||||
		request = DNSManager::Request::Login.new token
 | 
			
		||||
		send_now @server_fd.not_nil!, request
 | 
			
		||||
		send_now request
 | 
			
		||||
		parse_message [ DNSManager::Response::Success ], read
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	# Adding a full zone.
 | 
			
		||||
	def user_zone_add(zone : DNSManager::Storage::Zone)
 | 
			
		||||
		request = DNSManager::Request::AddOrUpdateZone.new zone
 | 
			
		||||
		send_now @server_fd.not_nil!, request
 | 
			
		||||
		send_now request
 | 
			
		||||
		parse_message [ DNSManager::Response::Success, DNSManager::Response::InvalidZone ], read
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
# Admin stuff.
 | 
			
		||||
class DNSManager::Client < IPC::Client
 | 
			
		||||
	#
 | 
			
		||||
	# Admin stuff.
 | 
			
		||||
	#
 | 
			
		||||
 | 
			
		||||
	def admin_maintainance(key : String, subject : DNSManager::Request::Maintainance::Subject, value : Int32? = nil)
 | 
			
		||||
		request = DNSManager::Request::Maintainance.new(key,subject)
 | 
			
		||||
		if value
 | 
			
		||||
			request.value = value
 | 
			
		||||
		end
 | 
			
		||||
		send_now @server_fd.not_nil!, request
 | 
			
		||||
		send_now request
 | 
			
		||||
		parse_message [ DNSManager::Response::Success ], read
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	def send_now(msg : IPC::JSON)
 | 
			
		||||
		m = IPCMessage::TypedMessage.new msg.type.to_u8, msg.to_json
 | 
			
		||||
		write @server_fd, m
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	def send_now(type : Request::Type, payload)
 | 
			
		||||
		m = IPCMessage::TypedMessage.new type.value.to_u8, payload
 | 
			
		||||
		write @server_fd, m
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	def read
 | 
			
		||||
		slice = self.read @server_fd
 | 
			
		||||
		m = IPCMessage::TypedMessage.deserialize slice
 | 
			
		||||
		m.not_nil!
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										54
									
								
								src/main.cr
									
										
									
									
									
								
							
							
						
						
									
										54
									
								
								src/main.cr
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -24,22 +24,29 @@ require "./storage.cr"
 | 
			
		|||
require "./network.cr"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DNSManager::Service < IPC::Server
 | 
			
		||||
class DNSManager::Service < IPC
 | 
			
		||||
	property configuration    : Baguette::Configuration::DNSManager
 | 
			
		||||
	getter storage            : DNSManager::Storage
 | 
			
		||||
	getter logged_users       : Hash(Int32, AuthD::User::Public)
 | 
			
		||||
 | 
			
		||||
	property authd            : AuthD::Client
 | 
			
		||||
 | 
			
		||||
	def initialize(@configuration, @authd : AuthD::Client)
 | 
			
		||||
		@storage = DNSManager::Storage.new @configuration.storage_directory
 | 
			
		||||
	def initialize(@configuration, @authd_key : String)
 | 
			
		||||
		super()
 | 
			
		||||
		@storage = DNSManager::Storage.new @configuration.storage_directory, @configuration.recreate_indexes
 | 
			
		||||
 | 
			
		||||
		@logged_users       = Hash(Int32, AuthD::User::Public).new
 | 
			
		||||
 | 
			
		||||
		super @configuration.service_name
 | 
			
		||||
		# TODO: auth service isn't in the FDs pool.
 | 
			
		||||
		# If the service crashes, dnsmanagerd won't know it.
 | 
			
		||||
		@authd = AuthD::Client.new
 | 
			
		||||
		authd.key = @authd_key
 | 
			
		||||
 | 
			
		||||
		self.timer @configuration.ipc_timer
 | 
			
		||||
		self.service_init @configuration.service_name
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	def get_logged_user(event : IPC::Event::Events)
 | 
			
		||||
	def get_logged_user(event : IPC::Event)
 | 
			
		||||
		@logged_users[event.fd]?
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -47,10 +54,13 @@ class DNSManager::Service < IPC::Server
 | 
			
		|||
		@authd.decode_token token
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	def handle_request(event : IPC::Event::MessageReceived)
 | 
			
		||||
	def handle_request(event : IPC::Event)
 | 
			
		||||
		request_start = Time.utc
 | 
			
		||||
 | 
			
		||||
		request = DNSManager.requests.parse_ipc_json event.message
 | 
			
		||||
		array = event.message.not_nil!
 | 
			
		||||
		slice = Slice.new array.to_unsafe, array.size
 | 
			
		||||
		message = IPCMessage::TypedMessage.deserialize slice
 | 
			
		||||
		request = DNSManager.requests.parse_ipc_json message.not_nil!
 | 
			
		||||
 | 
			
		||||
		if request.nil?
 | 
			
		||||
			raise "unknown request type"
 | 
			
		||||
| 
						 | 
				
			
			@ -81,42 +91,39 @@ class DNSManager::Service < IPC::Server
 | 
			
		|||
		# in the responses. Allows identifying responses easily.
 | 
			
		||||
		response.id = request.id
 | 
			
		||||
 | 
			
		||||
		send event.fd, response
 | 
			
		||||
		schedule event.fd, response
 | 
			
		||||
 | 
			
		||||
		duration = Time.utc - request_start
 | 
			
		||||
 | 
			
		||||
		response_str = response.class.name.sub /^DNSManager::Response::/, ""
 | 
			
		||||
		response_name = response.class.name.sub /^DNSManager::Response::/, ""
 | 
			
		||||
 | 
			
		||||
		if response.is_a? DNSManager::Response::Error
 | 
			
		||||
			Baguette::Log.warning ">> #{response_str} (#{response.reason})"
 | 
			
		||||
			Baguette::Log.warning ">> #{response_name} (#{response.reason})"
 | 
			
		||||
		else
 | 
			
		||||
			Baguette::Log.debug ">> #{response_str} (Total duration: #{duration})"
 | 
			
		||||
			Baguette::Log.debug ">> #{response_name} (Total duration: #{duration})"
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	def run
 | 
			
		||||
		Baguette::Log.title "Starting #{@configuration.service_name}"
 | 
			
		||||
 | 
			
		||||
		@base_timer = configuration.ipc_timer
 | 
			
		||||
		@timer      = configuration.ipc_timer
 | 
			
		||||
 | 
			
		||||
		self.loop do |event|
 | 
			
		||||
			begin
 | 
			
		||||
				case event
 | 
			
		||||
				when IPC::Event::Timer
 | 
			
		||||
				case event.type
 | 
			
		||||
				when LibIPC::EventType::Timer
 | 
			
		||||
					Baguette::Log.debug "Timer" if @configuration.print_ipc_timer
 | 
			
		||||
 | 
			
		||||
				when IPC::Event::Connection
 | 
			
		||||
				when LibIPC::EventType::Connection
 | 
			
		||||
					Baguette::Log.debug "connection from #{event.fd}"
 | 
			
		||||
 | 
			
		||||
				when IPC::Event::Disconnection
 | 
			
		||||
				when LibIPC::EventType::Disconnection
 | 
			
		||||
					Baguette::Log.debug "disconnection from #{event.fd}"
 | 
			
		||||
					@logged_users.delete event.fd
 | 
			
		||||
 | 
			
		||||
				when IPC::Event::MessageSent
 | 
			
		||||
				when LibIPC::EventType::MessageTx
 | 
			
		||||
					Baguette::Log.debug "message sent to #{event.fd}"
 | 
			
		||||
 | 
			
		||||
				when IPC::Event::MessageReceived
 | 
			
		||||
				when LibIPC::EventType::MessageRx
 | 
			
		||||
					Baguette::Log.debug "message received from #{event.fd}"
 | 
			
		||||
					handle_request event
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -125,7 +132,7 @@ class DNSManager::Service < IPC::Server
 | 
			
		|||
					if event.responds_to?(:fd)
 | 
			
		||||
						fd = event.fd
 | 
			
		||||
						Baguette::Log.warning "closing #{fd}"
 | 
			
		||||
						remove_fd fd
 | 
			
		||||
						close fd
 | 
			
		||||
						@logged_users.delete fd
 | 
			
		||||
					end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -206,10 +213,9 @@ def main
 | 
			
		|||
		exit 0
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	authd = AuthD::Client.new
 | 
			
		||||
	authd.key = authd_configuration.shared_key.not_nil!
 | 
			
		||||
	authd_key = authd_configuration.shared_key.not_nil!
 | 
			
		||||
 | 
			
		||||
	service = DNSManager::Service.new configuration, authd
 | 
			
		||||
	service = DNSManager::Service.new configuration, authd_key
 | 
			
		||||
	service.run
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ require "ipc"
 | 
			
		|||
require "json"
 | 
			
		||||
 | 
			
		||||
class IPC::JSON
 | 
			
		||||
	def handle(service : IPC::Server, event : IPC::Event::Events)
 | 
			
		||||
	def handle(service : IPC, event : IPC::Event)
 | 
			
		||||
		raise "unimplemented"
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ class DNSManager::Request
 | 
			
		|||
		def initialize(@key, @subject)
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event::Events)
 | 
			
		||||
		def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event)
 | 
			
		||||
			# This request means serious business.
 | 
			
		||||
			raise AdminAuthorizationException.new if key != dnsmanagerd.authd.key
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@ class DNSManager::Request
 | 
			
		|||
		def initialize(@token)
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event::Events)
 | 
			
		||||
		def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event)
 | 
			
		||||
			user, _ = dnsmanagerd.decode_token token
 | 
			
		||||
			dnsmanagerd.logged_users[event.fd] = user
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ class DNSManager::Request
 | 
			
		|||
		def initialize(@zone)
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event::Events)
 | 
			
		||||
		def handle(dnsmanagerd : DNSManager::Service, event : IPC::Event)
 | 
			
		||||
			user = dnsmanagerd.get_logged_user event
 | 
			
		||||
			raise NotLoggedException.new if user.nil?
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,13 +12,21 @@ class DNSManager::Storage
 | 
			
		|||
	getter zones             : DODB::CachedDataBase(Zone)
 | 
			
		||||
	getter zones_by_domain   : DODB::Index(Zone)
 | 
			
		||||
 | 
			
		||||
	def initialize(@root : String)
 | 
			
		||||
	def initialize(@root : String, reindex : Bool = false)
 | 
			
		||||
		@user_data         = DODB::CachedDataBase(UserData).new "#{@root}/user-data"
 | 
			
		||||
		@user_data_by_uid  = @user_data.new_index "uid", &.uid.to_s
 | 
			
		||||
		@zones             = DODB::CachedDataBase(Zone).new "#{@root}/zones"
 | 
			
		||||
		@zones_by_domain   = @zones.new_index "domain", &.domain
 | 
			
		||||
 | 
			
		||||
		Baguette::Log.info "storage initialized"
 | 
			
		||||
 | 
			
		||||
		if reindex
 | 
			
		||||
			Baguette::Log.debug "Reindexing user data..."
 | 
			
		||||
			@user_data.reindex_everything!
 | 
			
		||||
			Baguette::Log.debug "Reindexing zones..."
 | 
			
		||||
			@zones.reindex_everything!
 | 
			
		||||
			Baguette::Log.debug "Reindexed!"
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	def get_user_data(uid : Int32)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue