theforeman/foreman

View on GitHub
app/services/foreman/render_templates_from_folder.rb

Summary

Maintainability
A
45 mins
Test Coverage
module Foreman
  class RenderTemplatesFromFolder
    class ProvisioningTemplateFromFolder < ::ProvisioningTemplate
      self.table_name = 'templates'
      attr_accessor :template_path, :source_directory
    end

    attr_reader :source_directory
    attr_accessor :errors

    delegate :logger, to: :Rails

    def self.instance(source_directory:)
      @instances ||= {}
      @instances[source_directory] ||= new(source_directory: source_directory)
    end

    def self.clear_instances
      @instances = {}
    end

    def initialize(source_directory:)
      @source_directory = source_directory
      @errors = {}
    end

    def render_all
      self.errors = {}
      templates.each do |template|
        next if template.snippet
        if template.operatingsystems.empty?
          logger.debug "Skipping template #{template.name} because it's not associated to any operating system."
          next
        end
        begin
          render_template(template)
        rescue StandardError => e
          errors[template] = e.message
        end
      end
      errors.empty?
    end

    def render_template(template)
      source = source_klass.new(template)
      scope = Foreman::Renderer.get_scope(host: host(template), source: source)
      Foreman::Renderer.render(source, scope)
    end

    def templates
      @templates ||= files.map { |filepath| load_file(filepath) }
    end

    def snippets
      templates.select(&:snippet?)
    end

    def load_file(filepath)
      content = File.read(filepath)
      metadata = Template.parse_metadata(content).deep_symbolize_keys
      name = metadata[:name]
      raise "Could not read name from metadata in template #{filepath}." unless name.present?
      kind = metadata[:kind]
      snippet = (kind == 'snippet') || !!metadata[:snippet]
      oses = metadata[:oses] || []
      operatingsystems = oses.map { |os| build_operatingsystem(name: os) }.compact
      ProvisioningTemplateFromFolder.new(
        template_path: filepath, source_directory: source_directory,
        name: name, template: content,
        template_kind: TemplateKind.new(name: kind),
        snippet: snippet, operatingsystems: operatingsystems
      )
    end

    def host(template)
      operatingsystem = template.operatingsystems.first
      build_host(operatingsystem: operatingsystem)
    end

    private

    def source_klass
      Foreman::Renderer::Source::Directory
    end

    def files
      @files ||= Dir.glob(File.join(source_directory, '**', '*.erb'))
    end

    def build_architecture(osfamily:)
      architecture_name = case osfamily
                          when 'Solaris'
                            'sparc'
                          when 'VRP'
                            'ASIC'
                          else
                            'x86_64'
                          end
      Architecture.new(
        name: architecture_name
      )
    end

    def build_operatingsystem(name:)
      family = Operatingsystem.deduce_family(name)
      return unless family
      architecture = build_architecture(osfamily: family)
      family.constantize.new(
        name: name,
        major: 7,
        minor: 6,
        family: family,
        architectures: [architecture]
      )
    end

    def build_medium(operatingsystem:)
      case operatingsystem.family
      when 'Solaris'
        Medium.new(
          name: 'Solaris Medium',
          path: 'http://www.example.com/vol/solgi_5.10/sol$minor_$release_$arch',
          media_path: 'www.example.com:/vol/solgi_5.10/sol$minor_$release_$arch',
          config_path: 'www.example.com:/vol/jumpstart',
          image_path: 'www.example.com:/vol/solgi_5.10/sol$minor_$release_$arch/flash/',
          os_family: operatingsystem.family
        )
      else
        Medium.new(
          name: 'Example Medium',
          path: 'http://www.example.com/path/',
          os_family: operatingsystem.family
        )
      end
    end

    def build_host(operatingsystem:)
      medium = build_medium(operatingsystem: operatingsystem)
      domain = Domain.new(
        name: 'example.com'
      )
      subnet = Subnet.new(
        name: 'TEST-NET-1',
        network: '192.0.2.0'
      )
      medium.operatingsystems << operatingsystem
      operatingsystem.media << medium
      Host.new(
        architecture: operatingsystem.architectures.first,
        medium: medium,
        domain: domain,
        operatingsystem: operatingsystem,
        subnet: subnet,
        root_pass: 'securepassword',
        disk: 'fake disk layout',
        name: 'testhost',
        pxe_loader: 'Grub2 UEFI SecureBoot',
        mac: '00-11-22-33-44-55',
        managed: true
      )
    end
  end
end