Skip to content

Commit

Permalink
First draft of key search #4
Browse files Browse the repository at this point in the history
  • Loading branch information
oneiros committed Aug 30, 2022
1 parent 080f8ee commit 9a10a5b
Show file tree
Hide file tree
Showing 22 changed files with 251 additions and 32 deletions.
4 changes: 4 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,9 @@ AllCops:
- config/environments/*
- vendor/**/*
- .vendor/**/*
Naming/PredicateName:
ForbiddenPrefixes:
- "is_"
- "have_"
Rails/I18nLocaleTexts:
Enabled: false
20 changes: 20 additions & 0 deletions app/controllers/files_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class FilesController < ApplicationController
before_action :load_environments
before_action :load_key

add_breadcrumb "Home", :root_path
add_breadcrumb "Environments", :environments_path

def index
@files_and_values_by_hierarchy = DataFile.search(@environment, @key)

add_breadcrumb @environment, environment_nodes_path(@environment)
add_breadcrumb @key, environment_key_files_path(@environment, @key)
end

private

def load_key
@key = Key.new(environment: @environment, name: params[:key_id].squish)
end
end
6 changes: 3 additions & 3 deletions app/controllers/values_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def update
@value.update(params[:value], node: @node)

redirect_to environment_node_key_path(@environment, @node, @key),
notice: "Value was saved successfully"
notice: "Value was saved successfully"
end

def destroy
Expand All @@ -16,8 +16,8 @@ def destroy
@value.destroy(node: @node)

redirect_to environment_node_key_path(@environment, @node, @key),
status: :see_other,
notice: "Value was removed successfully"
status: :see_other,
notice: "Value was removed successfully"
end

private
Expand Down
14 changes: 14 additions & 0 deletions app/javascript/controllers/text_input_navigation_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Controller } from "@hotwired/stimulus"
import { Turbo } from "@hotwired/turbo-rails"

// Connects to data-controller="text-input-navigation"
export default class extends Controller {
static targets = ["input"]
static values = {placeholder: String, url: String}

navigate() {
const trimmedValue = this.inputTarget.value.trim()
const url = this.urlValue.replace(this.placeholderValue, trimmedValue);
Turbo.visit(url);
}
}
24 changes: 21 additions & 3 deletions app/models/data_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,26 @@ class DataFile < HieraModel

delegate :environment, to: :hierarchy

def self.search(environment, key)
hierarchies = {}
result = {}
HieraData.new(environment.name).files_including(key.name).each do |file|
hierarchies[file[:hierarchy_name]] ||= Hierarchy.new(
environment: environment,
name: file[:hierarchy_name],
backend: file[:hierarchy_backend]
)
data_file = new(
hierarchy: hierarchies[file[:hierarchy_name]],
path: file[:path]
)
value = Value.new(data_file: data_file, key: key, value: file[:value])
result[hierarchies[file[:hierarchy_name]]] ||= {}
result[hierarchies[file[:hierarchy_name]]][data_file] = value
end
result
end

def initialize(attributes = {})
super(attributes)
file_attributes = hiera_data.file_attributes(hierarchy.name, path, facts: node&.facts)
Expand All @@ -27,9 +47,7 @@ def has_key?(key)
end

def value_for(key:)
raw_value = if has_key?(key)
hiera_data.value_in_file(hierarchy.name, path, key.name, facts: node&.facts)
end
raw_value = (hiera_data.value_in_file(hierarchy.name, path, key.name, facts: node&.facts) if has_key?(key))
Value.new(data_file: self, key: key, value: raw_value)
end

Expand Down
24 changes: 21 additions & 3 deletions app/models/hiera_data.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# rubocop:disable Metrics/ClassLength
class HieraData
class EnvironmentNotFound < StandardError; end

Expand Down Expand Up @@ -32,7 +33,7 @@ def file_attributes(hierarchy_name, path, facts: nil)
{
exist: file.exist?,
writable: file.writable?,
replaced_from_git: file.replaced_from_git?,
replaced_from_git: file.replaced_from_git?
}
end

Expand All @@ -47,9 +48,9 @@ def value_in_file(hierarchy_name, path, key, facts: {})
file.content_for_key(key)
end

def search_key(hierarchy_name, key, facts:)
def search_key(hierarchy_name, key, facts: nil)
hierarchy = find_hierarchy(hierarchy_name)
files = hierarchy.resolved_paths(facts: facts)
files = facts ? hierarchy.resolved_paths(facts: facts) : hierarchy.candidate_files
search_results = {}
files.each do |path|
file = DataFile.new(path: hierarchy.datadir.join(path), facts: facts)
Expand All @@ -64,6 +65,22 @@ def search_key(hierarchy_name, key, facts:)
search_results
end

def files_including(key)
hierarchies.flat_map do |hierarchy|
search_results = search_key(hierarchy.name, key)
search_results.map do |path, search_result|
next unless search_result[:key_present]

{
path: path,
hierarchy_name: hierarchy.name,
hierarchy_backend: hierarchy.backend,
value: search_result[:value]
}
end
end.compact!
end

def write_key(hierarchy_name, path, key, value, facts: {})
hierarchy = find_hierarchy(hierarchy_name)
read_file = DataFile.new(path: hierarchy.datadir.join(path), facts: facts)
Expand Down Expand Up @@ -120,3 +137,4 @@ def find_hierarchy(name)
config.hierarchies.find { |h| h.name == name }
end
end
# rubocop:enable Metrics/ClassLength
7 changes: 7 additions & 0 deletions app/models/hiera_data/hierarchy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ def resolved_paths(facts:)
end
end

def candidate_files
paths.flat_map do |path|
globbed_path = Interpolation.replace_variables_with_globs(path)
Interpolation.interpolate_globs(path: globbed_path, datadir: datadir)
end
end

private

def setup_paths
Expand Down
4 changes: 4 additions & 0 deletions app/models/hiera_data/interpolation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,9 @@ def interpolate_facts(path:, facts:)
value || variable_string
end
end

def replace_variables_with_globs(path)
path.gsub(VARIABLE_REGEXP, "*")
end
end
end
20 changes: 20 additions & 0 deletions app/models/key_file.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class KeyFile
include ActiveModel::Model
include ActiveModel::Attributes

attribute :environment
attribute :hierarchy_name, :string
attribute :path, :string
attribute :value, :string

def self.all(environment, key)
HieraData.new(environment.name).files_including(key).map do |file|
new(
environment: environment,
path: file[:path],
hierarchy_name: file[:hierarchy_name],
value: file[:value]
)
end
end
end
2 changes: 1 addition & 1 deletion app/models/value.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def encrypted?
end

def update(new_value, node: nil)
parsed_value = YAML.load(new_value)
parsed_value = YAML.safe_load(new_value)
facts = node ? node.facts : {}
hiera_data.write_key(data_file.hierarchy.name, data_file.path, key.name, parsed_value, facts: facts)
end
Expand Down
6 changes: 6 additions & 0 deletions app/views/files/_search.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<%= form_tag "", data: {controller: "text-input-navigation", action: "submit->text-input-navigation#navigate", text_input_navigation_placeholder_value: "KEY_ID", text_input_navigation_url_value: environment_key_files_path(key_id: "KEY_ID")} do |form| %>
<div class="form-group">
<%= label_tag :key, "Search for a key" %>
<%= text_field_tag "key", @key&.name, class: "form-control", required: true, data: {text_input_navigation_target: "input"} %>
</div>
<% end %>
66 changes: 66 additions & 0 deletions app/views/files/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<div class="row">
<div class="col-6">
<%= render "environments/select_environment" %>
</div>
<div class="col-6">
<%= render "search" %>
</div>
</div>

<div class="row mt-4">
<div class="col-12">
<h2>Search Results</h2>
<p class="lead">
<% if @files_and_values_by_hierarchy.any? %>
Found key
<code><%= @key.name %></code>
in
<b><%= t(".file", count: @files_and_values_by_hierarchy.values.map { |f| f.size }.sum) %></b>.
<% else %>
Could not find key
<code><%= @key.name %></code>
in any files.
<% end %>
</p>
</div>
</div>

<div class="row mt-4">
<div class="col-12">
<% index = 0 %>
<% @files_and_values_by_hierarchy.each do |hierarchy, files_and_values| %>
<div class="accordion mb-2">
<div class="card">
<div class="card-body">
<b><%= hierarchy.name %></b>
<span class="badge badge-primary text-light"><%= hierarchy.backend %></span>
</div>
</div>
<% files_and_values.each do |file, value| %>
<% index += 1 %>
<div class="card">
<div class="card-header" id="path-<%= index %>">
<h2 class="mb-0">
<button class="btn btn-link btn-block text-left d-flex justify-content-between" type="button" data-toggle="collapse" data-target="#collapse-<%= index %>" aria-expanded="true" aria-controls="collapse-<%= index %>">
<span>
<b><%= file.path %></b>
<% if value&.encrypted? %>
<span class="text-danger">
<%= icon("lock-fill") %>
</span>
<% end %>
</span>
</button>
</h2>
</div>
<div id="collapse-<%= index %>" class="collapse" aria-labelledby="path-<%= index %>">
<div class="card-body">
<pre><%= value.value %></pre>
</div>
</div>
</div>
<% end %>
</div>
<% end %>
</div>
</div>
8 changes: 8 additions & 0 deletions app/views/keys/_select_env_and_node.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="row">
<div class="col-6">
<%= render "environments/select_environment" %>
</div>
<div class="col-6">
<%= render "nodes/select_node" %>
</div>
</div>
2 changes: 1 addition & 1 deletion app/views/keys/index.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%= render "nodes/select_node" %>
<%= render "select_env_and_node" %>

<div class="row mt-4">
<div class="col-6">
Expand Down
2 changes: 1 addition & 1 deletion app/views/keys/show.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%= render "nodes/select_node" %>
<%= render "select_env_and_node" %>

<div class="row mt-4">
<div class="col-6">
Expand Down
27 changes: 10 additions & 17 deletions app/views/nodes/_select_node.html.erb
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
<div class="row">
<div class="col-6">
<%= render "environments/select_environment" %>
<%= form_tag "" do |form| %>
<div class="form-group">
<%= label_tag :node, "Select node" %>
<select name="node" data-controller="slim-select select-navigation" data-action="change->select-navigation#navigate">
<option value="" <% "selected" if @node.nil? %> data-url="<%= environment_nodes_path(@environment) %>"></option>
<% @nodes.each do |node| %>
<option data-url="<%= environment_node_keys_path(@environment, node) %>" <%= "selected" if node == @node %>><%= node.hostname %></option>
<% end %>
</select>
</div>
<div class="col-6">
<%= form_tag "" do |form| %>
<div class="form-group">
<%= label_tag :node, "Select node" %>
<select name="node" data-controller="slim-select select-navigation" data-action="change->select-navigation#navigate">
<option value="" <% "selected" if @node.nil? %> data-url="<%= environment_nodes_path(@environment) %>"></option>
<% @nodes.each do |node| %>
<option data-url="<%= environment_node_keys_path(@environment, node) %>" <%= "selected" if node == @node %>><%= node.hostname %></option>
<% end %>
</select>
</div>
<% end %>
</div>
</div>
<% end %>
10 changes: 9 additions & 1 deletion app/views/nodes/index.html.erb
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
<%= render "select_node" %>
<div class="row">
<div class="col-6">
<%= render "environments/select_environment" %>
</div>
<div class="col-6">
<%= render "nodes/select_node" %>
<%= render "files/search" %>
</div>
</div>
6 changes: 5 additions & 1 deletion config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,8 @@
# available at https://guides.rubyonrails.org/i18n.html.

en:
hello: "Hello world"
files:
index:
file:
one: "%{count} file"
other: "%{count} files"
6 changes: 6 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# rubocop:disable Metrics/BlockLength
Rails.application.routes.draw do
resources :environments, only: :index do
resources :hierarchies, only: [] do
Expand All @@ -6,6 +7,10 @@
resources :encrypted_values, only: [:create]
end

resources :keys, only: [] do
resources :files, only: [:index]
end

resources :nodes, only: :index, constraints: {id: /.+/} do
if Rails.configuration.hdm['read_only']
resources :keys, only: [:index, :show]
Expand Down Expand Up @@ -33,3 +38,4 @@

root to: 'page#index'
end
# rubocop:enable Metrics/BlockLength
7 changes: 7 additions & 0 deletions test/controllers/files_controller_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require "test_helper"

class FilesControllerTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
end
Loading

0 comments on commit 9a10a5b

Please sign in to comment.