Skip to content

Commit

Permalink
First version of the ssh_import proposal
Browse files Browse the repository at this point in the history
  • Loading branch information
ancorgs committed May 16, 2016
1 parent eeb6f80 commit b9acb1d
Show file tree
Hide file tree
Showing 5 changed files with 255 additions and 18 deletions.
2 changes: 2 additions & 0 deletions src/clients/ssh_import_proposal.rb
@@ -0,0 +1,2 @@
require "installation/clients/ssh_import_proposal"
Yast::SshImportProposalClient.run
9 changes: 9 additions & 0 deletions src/lib/installation/clients/copy_files_finish.rb
Expand Up @@ -29,6 +29,7 @@
# Jiri Srain <jsrain@suse.cz>
#
require "fileutils"
require "installation/ssh_config"

module Yast
class CopyFilesFinishClient < Client
Expand Down Expand Up @@ -202,6 +203,9 @@ def main
# bugzila #328126
# Copy 70-persistent-cd.rules ... if not updating
CopyHardwareUdevRules() if !Mode.update

# fate#319624
copy_ssh_files
else
Builtins.y2error("unknown function: %1", @func)
@ret = nil
Expand Down Expand Up @@ -335,6 +339,11 @@ def CopyHardwareUdevRules
nil
end

def copy_ssh_files
log.info "Copying SSH keys and config files"
::Installation::SshConfig.export(Installation.destdir)
end

# Prevent from re-defining client class
# Re-defining would produce warnings that constants were already initialized
end unless defined? CopyFilesFinishClient
Expand Down
54 changes: 36 additions & 18 deletions src/lib/installation/clients/inst_pre_install.rb
Expand Up @@ -18,6 +18,9 @@
# To contact Novell about this file by physical or electronic mail, you may find
# current contact information at www.novell.com.
# ------------------------------------------------------------------------------

require "installation/ssh_config"

module Yast
class InstPreInstallClient < Client
include Yast::Logger
Expand Down Expand Up @@ -55,6 +58,7 @@ def main
from: "any",
to: "list <map>"
)
@copy_items ||= []

@copy_items.each do |one_copy_item|
item_id = one_copy_item["id"]
Expand Down Expand Up @@ -85,7 +89,10 @@ def main
end
end

read_users
each_mounted_partition do |device, mount_point|
read_users(device, mount_point) if read_users?
read_ssh_info(device, mount_point)
end

# free the memory
@useful_partitions = nil
Expand Down Expand Up @@ -205,23 +212,6 @@ def FindAndCopyNewestFiles(copy_to, wanted_files, optional_files)
nil
end

# Stores all found user databases (/etc/passwd and friends) into
# UsersDatabase.all, so it can be used during the users import step
def read_users
require_users_database
return unless defined? Users::UsersDatabase
each_mounted_partition do |device, mount_point|
log.info "Reading users information from #{device}"
Users::UsersDatabase.import(mount_point)
end
end

def require_users_database
require "users/users_database"
rescue LoadError
log.error "UsersDatabase not found. YaST2-users is missing, old or broken."
end

def Initialize
Builtins.y2milestone("Evaluating all current partitions")

Expand Down Expand Up @@ -300,6 +290,34 @@ def Initialize

protected

# Checks whether it's possible to read the existing users databases
def read_users?
@read_users ||= begin
require_users_database
defined? Users::UsersDatabase
end
end

def require_users_database
require "users/users_database"
rescue LoadError
log.error "UsersDatabase not found. YaST2-users is missing, old or broken."
end

# Stores the users database (/etc/passwd and friends) of a given partition
# in UsersDatabase.all, so it can be used during the users import step
def read_users(device, mount_point)
log.info "Reading users information from #{device}"
Users::UsersDatabase.import(mount_point)
end

# Stores the SSH configuration of a given partition in SshConfig.all
# @see CopyFilesFinishClient and SshImportProposalClient
def read_ssh_info(device, mount_point)
log.info "Reading SSH information from #{device}"
::Installation::SshConfig.import(mount_point, device)
end

def each_mounted_partition(&block)
mnt_tmpdir = "#{Directory.tmpdir}/tmp_mnt_for_check"
mnt_tmpdir = SystemFilesCopy.CreateDirectoryIfMissing(mnt_tmpdir)
Expand Down
103 changes: 103 additions & 0 deletions src/lib/installation/clients/ssh_import_proposal.rb
@@ -0,0 +1,103 @@
require "installation/proposal_client"
require "installation/dialogs/ssh_import"
require "installation/ssh_config"

module Yast
# Proposal client for bootloader configuration
class SshImportProposalClient < ::Installation::ProposalClient
include Yast::I18n

@@calculated = false

def initialize
Yast.import "UI"
textdomain "installation"
end

protected

def description
{
# proposal part - bootloader label
"rich_text_title" => _("Import SSH Configuration and Keys"),
# menubutton entry
"menu_title" => _("&Import SSH Configuration and Keys"),
"id" => "ssh_import"
}
end

def make_proposal(attrs)
if !@@calculated || attrs["force_reset"]
@@calculated = true
set_default_values
end
update_ssh_configs
{
"preformatted_proposal" => preformatted_proposal,
"links" => ["ssh_import"]
}
end

# To ensure backwards compatibility, the default proposal is to copy all
# the ssh keys in the most recently accessed config and to not copy any
# additional config file
def set_default_values
@@device = default_ssh_config.device
@@copy_config = false
end

# Syncs the status of SshConfig.all with the settings in the proposal
#
# It updates the #to_export flag for all the SSH keys and config files.
def update_ssh_configs
all_ssh_configs.each do |config|
selected = config.device == @@device
config.config_files.each { |f| f.to_export = (selected && @@copy_config) }
config.keys.each { |k| k.to_export = selected }
end
end

def default_ssh_config
@default_ssh_config ||= all_ssh_configs.select(&:keys_atime).max_by(&:keys_atime)
end

def all_ssh_configs
@all_ssh_configs ||= ::Installation::SshConfig.all
end

def preformatted_proposal
if all_ssh_configs.empty?
return _("No previous Linux installation found - not importing any SSH Key")
end
if @@device.nil?
res = _("No existing SSH keys will be copied")
else
ssh_config = all_ssh_configs.detect { |c| c.device == @@device }
partition = ssh_config.system_name
if @@copy_config
# TRANSLATORS: %s is the name of a Linux system found in the hard
# disk, like 'openSUSE 13.2'
res = _("SSH keys and configuration will be copied from %s") % partition
else
# TRANSLATORS: %s is the name of a Linux system found in the hard
# disk, like 'openSUSE 13.2'
res = _("SSH keys will be copied from %s") % partition
end
end
res += " " + _("(<a href=%s>change</a>)") % '"ssh_import"'
res
end

def ask_user(param)
log.info "Asking user which SSH keys to import"
user_input = Yast::SshImportDialog.new(@@device, @@copy_config).run
if user_input
log.info "SshImportDialog result: #{user_input}"
@@device = user_input[:device]
@@copy_config = user_input[:copy_config]
end

{ "workflow_sequence" => :next }
end
end
end
105 changes: 105 additions & 0 deletions src/lib/installation/dialogs/ssh_import.rb
@@ -0,0 +1,105 @@
# Copyright (c) 2016 SUSE LLC.
# All Rights Reserved.

# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 or 3 of the GNU General
# Public License as published by the Free Software Foundation.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, contact SUSE LLC.

# To contact SUSE about this file by physical or electronic mail,
# you may find current contact information at www.suse.com

require "yast"
require "ui/dialog"
require "installation/ssh_config"

module Yast
class SshImportDialog < ::UI::Dialog
def initialize(device, copy_config)
super()

Yast.import "UI"
Yast.import "Label"

textdomain "installation"

@device = device
@copy_config = copy_config
end

# Event callback for the 'ok' button
def ok_handler
partition = UI.QueryWidget(Id(:device), :Value)
partition = nil if partition == :none
copy_config = UI.QueryWidget(Id(:copy_config), :Value)
finish_dialog(device: partition, copy_config: copy_config)
end

private

attr_reader :device, :copy_config

def partitions
@partitions ||= ::Installation::SshConfig.all.reject { |c| c.keys.empty? }
end

def dialog_content
VBox(
Heading(_("System to Import SSH Keys from")),
HBox(
HStretch(),
VBox(
partitions_list_widget,
VSpacing(0.5),
Left(copy_config_widget)
),
HStretch()
),
VSpacing(0.5),
HBox(
PushButton(Id(:ok), Opt(:default), Label.OKButton),
PushButton(Id(:cancel), Label.CancelButton)
)
)
end

def dialog_options
Opt(:decorated)
end

def partitions_list_widget
part_widgets = partitions.map do |partition|
Left(partition_widget(partition))
end

RadioButtonGroup(
Id(:device),
VBox(
# TRANSLATORS: option to select no partition for SSH keys import
Left(RadioButton(Id(:none), _("None"), @device.nil?)),
*part_widgets
)
)
end

def partition_widget(partition)
dev = partition.device
strings = {system_name: partition.system_name, device: dev}
# TRANSLATORS: system_name is a string like "openSUSE 13.2", device
# is a string like /dev/sda1
name = _("%{system_name} at %{device}") % strings
RadioButton(Id(dev), name, device == dev)
end

def copy_config_widget
CheckBox(Id(:copy_config), _("Copy whole SSH configuration"), @copy_config)
end
end
end

0 comments on commit b9acb1d

Please sign in to comment.