├── .github └── workflows │ └── code-style-review.yaml ├── .gitignore ├── .haml-lint.yml ├── .haml-lint_todo.yml ├── .rubocop.yml ├── .rubocop_todo.yml ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── CONTRIBUTORS.md ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── PLUGINS.md ├── README.markdown ├── Rakefile ├── VERSION ├── acceptance └── tests │ └── dashboard_rake_tasks.rb ├── app ├── assets │ ├── javascripts │ │ ├── ajax_helper.js │ │ ├── application.js │ │ ├── application.radiator.js │ │ ├── autorefresh.js │ │ ├── dashboard.js │ │ ├── jqplot.barRenderer.js │ │ ├── jqplot.canvasAxisTickRenderer.js │ │ ├── jqplot.canvasTextRenderer.js │ │ ├── jqplot.categoryAxisRenderer.js │ │ ├── jqplot.highlighter.js │ │ ├── jqplot.pointLabels.js │ │ ├── jquery.colorbox.js │ │ ├── jquery.cookie.js │ │ ├── jquery.form.js │ │ ├── jquery.jqplot.js │ │ ├── jquery.livequery.js │ │ ├── jquery.placeholders.js │ │ ├── jquery.templating.js │ │ ├── jquery.tipsy.js │ │ ├── jquery.tokeninput.js │ │ ├── jquery.ui.combobox.js │ │ ├── radiator.js │ │ ├── search.js │ │ └── validation_response.js │ └── stylesheets │ │ ├── application.css │ │ ├── application.radiator.css │ │ ├── colorbox.css │ │ ├── dashboard.scss │ │ ├── forms.css │ │ ├── help.scss │ │ ├── images │ │ ├── border.png │ │ ├── controls.png │ │ ├── grid.png │ │ ├── header.png │ │ ├── icons │ │ │ ├── add.png │ │ │ ├── add_grey.png │ │ │ ├── add_light_grey.png │ │ │ ├── computer.png │ │ │ ├── delete.png │ │ │ ├── edit.png │ │ │ ├── failure.png │ │ │ ├── search.png │ │ │ └── success.png │ │ ├── internet_explorer │ │ │ ├── borderBottomCenter.png │ │ │ ├── borderBottomLeft.png │ │ │ ├── borderBottomRight.png │ │ │ ├── borderMiddleLeft.png │ │ │ ├── borderMiddleRight.png │ │ │ ├── borderTopCenter.png │ │ │ ├── borderTopLeft.png │ │ │ └── borderTopRight.png │ │ ├── loading.gif │ │ ├── loading_background.png │ │ ├── overlay.png │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ │ ├── ui-bg_flat_0_eeeeee_40x100.png │ │ ├── ui-bg_flat_100_5c80a8_40x100.png │ │ ├── ui-bg_flat_55_ffffff_40x100.png │ │ ├── ui-bg_flat_65_ffffff_40x100.png │ │ ├── ui-bg_flat_75_ffffff_40x100.png │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ ├── ui-bg_highlight-soft_100_f6f6f6_1x100.png │ │ ├── ui-bg_highlight-soft_25_0073ea_1x100.png │ │ ├── ui-bg_highlight-soft_50_dddddd_1x100.png │ │ ├── ui-icons_0073ea_256x240.png │ │ ├── ui-icons_454545_256x240.png │ │ ├── ui-icons_666666_256x240.png │ │ ├── ui-icons_ff0084_256x240.png │ │ ├── ui-icons_ffffff_256x240.png │ │ ├── white-overlay.png │ │ └── white-overlays.png │ │ ├── jquery.jqplot.css │ │ ├── jquery.ui.combobox.css │ │ ├── jquery.ui.custom.css │ │ ├── layout.css │ │ ├── links.css │ │ ├── mixins.scss │ │ ├── popups.css │ │ ├── radiator.scss │ │ ├── reset.css │ │ ├── tables.css │ │ ├── tipsy.css │ │ ├── token-input-facebook.css │ │ └── typography.css ├── controllers │ ├── application_controller.rb │ ├── delayed_job_failures_controller.rb │ ├── files_controller.rb │ ├── help_controller.rb │ ├── node_class_memberships_controller.rb │ ├── node_classes_controller.rb │ ├── node_group_class_memberships_controller.rb │ ├── node_group_memberships_controller.rb │ ├── node_groups_controller.rb │ ├── nodes_controller.rb │ ├── pages_controller.rb │ ├── radiator_controller.rb │ └── reports_controller.rb ├── helpers │ ├── application_helper.rb │ ├── conflict_analyzer.rb │ ├── conflict_html.rb │ ├── node_classes_helper.rb │ ├── node_groups_helper.rb │ ├── nodes_helper.rb │ ├── pages_helper.rb │ ├── paginate_scope_helper.rb │ ├── reports_helper.rb │ ├── status_helper.rb │ └── string_helper.rb ├── mailers │ └── .gitkeep ├── mixins │ └── searchable_index.rb ├── models │ ├── .gitkeep │ ├── application_record.rb │ ├── delayed_job_failure.rb │ ├── metric.rb │ ├── node.rb │ ├── node_class.rb │ ├── node_class_membership.rb │ ├── node_group.rb │ ├── node_group_class_membership.rb │ ├── node_group_edge.rb │ ├── node_group_membership.rb │ ├── parameter.rb │ ├── report.rb │ ├── report_log.rb │ ├── resource_event.rb │ ├── resource_status.rb │ ├── status.rb │ └── timeline_event.rb └── views │ ├── delayed_job_failures │ └── index.html.haml │ ├── help │ └── _node_status.html.haml │ ├── layouts │ ├── _radiator.html.haml │ └── application.html.haml │ ├── metrics │ └── _metrics_table.html.haml │ ├── node_class_memberships │ ├── _form.html.haml │ ├── edit.html.haml │ └── show.html.haml │ ├── node_classes │ ├── _actions.html.haml │ ├── _form.html.haml │ ├── edit.html.haml │ ├── index.html.haml │ ├── new.html.haml │ └── show.html.haml │ ├── node_group_class_memberships │ ├── _form.html.haml │ ├── edit.html.haml │ └── show.html.haml │ ├── node_groups │ ├── _actions.html.haml │ ├── _form.html.haml │ ├── _search.html.haml │ ├── edit.html.haml │ ├── index.html.haml │ ├── new.html.haml │ └── show.html.haml │ ├── nodes │ ├── _activity.html.haml │ ├── _description.html.haml │ ├── _facts.html.haml │ ├── _form.html.haml │ ├── _hidden.html.haml │ ├── _inspections.html.haml │ ├── _inventory_service.html.haml │ ├── _log_detail.html.haml │ ├── _nodes.html.haml │ ├── _reports.html.haml │ ├── _reports_table_tfoot.html.haml │ ├── _search.html.haml │ ├── edit.html.haml │ ├── index.html.haml │ ├── inventory_search.html.haml │ ├── new.html.haml │ └── show.html.haml │ ├── pages │ ├── _node_summary_row.haml │ ├── home.html.haml │ └── index.html.haml │ ├── parameters │ ├── _parameter.html.haml │ └── _parameter_input.html.haml │ ├── puppet │ ├── transaction │ │ └── reports │ │ │ └── _report.haml │ └── util │ │ └── logs │ │ └── _log.haml │ ├── reports │ ├── _log.html.haml │ ├── _metrics.html.haml │ ├── _report.html.haml │ ├── _report_status_icon.html.haml │ ├── _report_status_td.html.haml │ ├── _report_title.html.haml │ ├── _reports_table.html.haml │ ├── _resource_statuses.html.haml │ ├── index.html.haml │ └── show.html.haml │ ├── shared │ ├── _class_parameter_conflicts_table.html.haml │ ├── _classes.html.haml │ ├── _confirm.html.haml │ ├── _error.html.haml │ ├── _form_errors.html.haml │ ├── _global_nav.html.haml │ ├── _groups.html.haml │ ├── _inspector.html.haml │ ├── _node_manager_sidebar.html.haml │ ├── _node_manager_sidebar_for_type.html.haml │ ├── _node_summary.html.haml │ ├── _parameters.html.haml │ ├── _parameters_part1.html.haml │ ├── _parameters_part2.html.haml │ ├── _search.html.haml │ ├── _skiplink.html.haml │ ├── _skiptarget.html.haml │ ├── _tokenized_text_box.html.haml │ ├── _variable_conflicts_table.html.haml │ └── _variables.html.haml │ ├── statuses │ ├── _run_failure.html.haml │ ├── _run_time.html.haml │ └── show.html.haml │ └── timeline_events │ └── _timeline_event.html.haml ├── bin ├── bundle ├── delayed_job ├── external_node ├── rails ├── rake ├── setup ├── update └── yarn ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cable.yml ├── database.yml.example ├── database.yml.travis ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── 00_settings_reader_init.rb │ ├── 01_serialize_flash_as_hash.rb │ ├── ZZZ_load_plugin_initializers.rb │ ├── app_version_init.rb │ ├── application_controller_renderer.rb │ ├── assets.rb │ ├── backtrace_silencers.rb │ ├── check_migration_version.rb │ ├── clear_cached_assets.rb │ ├── content_security_policy.rb │ ├── cookies_serializer.rb │ ├── delayed_job.rb │ ├── filter_parameter_logging.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── requires.rb │ ├── safe_yaml.rb │ ├── sass.rb │ ├── session_store.rb │ ├── time_formats.rb │ └── wrap_parameters.rb ├── locales │ └── en.yml ├── preinitializer.rb ├── puma.rb ├── routes.rb ├── secrets.yml ├── settings.yml.example ├── spring.rb └── storage.yml ├── db ├── migrate │ ├── 20090916215745_basic_schema.rb │ ├── 20090916221313_create_node_group_memberships.rb │ ├── 20090917163433_create_node_classes.rb │ ├── 20090917163500_create_node_class_memberships.rb │ ├── 20090921151631_create_node_groups.rb │ ├── 20091025181245_create_node_group_class_memberships.rb │ ├── 20091025182048_add_parameters_to_node_groups.rb │ ├── 20091028174517_create_timeline_events.rb │ ├── 20091028210805_create_users.rb │ ├── 20091110002528_create_parameters.rb │ ├── 20091110005353_remove_parameters_from_node.rb │ ├── 20091116212418_create_node_group_edges.rb │ ├── 20091116235339_remove_parameters_from_node_groups.rb │ ├── 20091120013227_create_reports.rb │ ├── 20091130201400_add_url_to_node.rb │ ├── 20091208225308_add_reported_at_to_node.rb │ ├── 20091215194836_add_success_to_report.rb │ ├── 20091217192540_add_host_and_time_to_report.rb │ ├── 20091217212330_migrate_report_data.rb │ ├── 20100318131825_add_indexes.rb │ ├── 20100726070117_add_success_and_last_report_to_nodes.rb │ ├── 20100806181533_cleanup_node_memberships.rb │ ├── 20100810011613_change_report_report_field_size_to_be_larger.rb │ ├── 20100811204545_add_success_to_report_index.rb │ ├── 20100909191050_remove_duplicate_class_and_group_memberships.rb │ ├── 20100916183948_adjust_indexes_on_reports.rb │ ├── 20101109001012_add_status_to_reports.rb │ ├── 20101118222325_add_hidden_to_nodes.rb │ ├── 20101206225510_schematize_reports.rb │ ├── 20101229023023_add_baseline_report_id_to_nodes.rb │ ├── 20101230054456_drop_user_table.rb │ ├── 20110105015322_add_out_of_sync_count_to_resource_statuses.rb │ ├── 20110105231637_remove_source_description_from_resource_statuses.rb │ ├── 20110105231833_remove_source_description_from_resource_events.rb │ ├── 20110105233543_add_historical_value_to_resource_events.rb │ ├── 20110105233640_add_audited_to_resource_events.rb │ ├── 20110105234202_remove_tags_from_resource_events.rb │ ├── 20110106002514_add_skipped_to_resource_statuses.rb │ ├── 20110107233911_remove_out_of_sync_column.rb │ ├── 20110113012919_make_long_string_fields_into_text_fields.rb │ ├── 20110113013807_add_last_inspect_report_id_to_nodes.rb │ ├── 20110113183616_remove_unused_tables_and_models.rb │ ├── 20110113195253_rename_column_last_report_id_to_last_apply_report_id_on_nodes.rb │ ├── 20110114190814_add_failed_to_resource_statuses.rb │ ├── 20110130010154_remove_column_baseline_report_id_from_nodes.rb │ ├── 20110603183820_add_status_column_to_resource_statuses.rb │ ├── 20110614234202_create_delayed_jobs.rb │ ├── 20110620111500_create_delayed_job_failures.rb │ ├── 20110728195829_add_node_host_uniqueness_constraint.rb │ ├── 20110729201310_add_delayed_job_failure_backtrace.rb │ ├── 20111118204121_add_report_foreign_key_constraints.rb │ ├── 20120112195235_remove_url_from_nodes.rb │ ├── 20121111212016_add_queue_to_delayed_jobs.rb │ ├── 20130322105500_create_foreign_key_indexes.rb │ ├── 20130418063629_add_description_to_node_classes.rb │ ├── 20130418064011_add_description_to_node_groups.rb │ ├── 20140118072510_add_performance_indices.rb │ ├── 20140414051338_change_reports_to_blobs.rb │ ├── 20141217071943_add_environment_to_nodes.rb │ ├── 20150405234511_add_environment_to_reports.rb │ ├── 20150406035502_add_transaction_uuid_to_reports.rb │ ├── 20150406035704_add_containment_path_to_resource_statuses.rb │ ├── 20180612210108_add_catalog_uuid_to_reports.rb │ ├── 20180612210310_add_cached_catalog_status_to_reports.rb │ ├── 20180613224704_add_report_format6.rb │ ├── 20180614161626_add_report_format8.rb │ └── 20180614210435_add_report_format9.rb └── schema.rb ├── docs └── manual │ ├── bootstrapping.markdown │ ├── configuring.markdown │ ├── images │ └── background_tasks_pending.png │ ├── index.markdown │ ├── maintaining.markdown │ ├── rake_api.markdown │ └── upgrading.markdown ├── ext ├── build_defaults.yaml ├── debian │ ├── README.Debian │ ├── changelog.erb │ ├── compat │ ├── conf │ │ └── database.yml.template │ ├── control │ ├── copyright │ ├── default │ ├── dirs │ ├── doc │ │ └── examples │ │ │ ├── apache2-alias.conf │ │ │ ├── apache2-host.conf │ │ │ └── apache2-passenger.conf │ ├── docs │ ├── files │ ├── init │ ├── install │ ├── logrotate │ ├── po │ │ └── templates.pot │ ├── postinst │ ├── postrm │ ├── puppet-dashboard-workers.default │ ├── puppet-dashboard-workers.init │ ├── rmshebang.sh │ ├── rules │ └── source │ │ └── format ├── passenger │ └── dashboard-vhost.conf ├── project_data.yaml ├── puppet │ └── puppet_dashboard.rb └── redhat │ ├── puppet-dashboard-workers.init │ ├── puppet-dashboard-workers.service │ ├── puppet-dashboard.init │ ├── puppet-dashboard.logrotate │ ├── puppet-dashboard.service │ ├── puppet-dashboard.spec.erb │ ├── puppet-dashboard.sysconfig │ └── systemd-install.sh ├── lib ├── add_renderers.rb ├── assets │ └── .gitkeep ├── class_parameter_conflict_error.rb ├── core_callbacks.rb ├── csv_extensions.rb ├── data_generator.rb ├── find_by_id_or_name.rb ├── find_from_form.rb ├── has_parameters.rb ├── incorrect_report_kind.rb ├── node_classification_disabled_error.rb ├── node_group_graph.rb ├── parameter_conflict_error.rb ├── puppet │ └── report_sanitizer.rb ├── puppet_https.rb ├── read_only_enabled_error.rb ├── registry.rb ├── report_transformer.rb ├── settings_reader.rb ├── tasks │ ├── .gitkeep │ ├── classesgroups.rake │ ├── clean_sample_reports.rake │ ├── db_raw.rake │ ├── generate_and_import_samples.rake │ ├── generate_sample_reports.rake │ ├── generate_unresponsive_nodes.rake │ ├── import_reports.rake │ ├── install.rake │ ├── install_cleanup_cron.rake │ ├── node.rake │ ├── plugins.rake │ ├── prune_reports.rake │ ├── rake_helpers.rb │ ├── rspec_rcov.rake │ ├── schematize_reports.rake │ ├── scss.rake │ ├── summarize_reports.rake │ ├── timeline.rake │ └── update_report_data.rake └── trimmer.rb ├── log ├── .gitignore └── .gitkeep ├── public ├── 404.html ├── 422.html ├── 500.html ├── favicon.ico ├── images │ ├── close.gif │ ├── dashboard_logo.png │ ├── icons │ │ ├── add.png │ │ ├── add_grey.png │ │ ├── add_light_grey.png │ │ ├── bullet_green.png │ │ ├── bullet_red.png │ │ ├── bullet_toggle_minus.png │ │ ├── bullet_toggle_plus.png │ │ ├── cancel.png │ │ ├── changed.png │ │ ├── close.png │ │ ├── computer.png │ │ ├── delayed-job-failure.png │ │ ├── delayed-job-ok.png │ │ ├── delayed-job-warning.png │ │ ├── delete.png │ │ ├── edit.png │ │ ├── error.png │ │ ├── failed.png │ │ ├── help.png │ │ ├── inspect.png │ │ ├── notice.png │ │ ├── pending.png │ │ ├── popup.png │ │ ├── search.png │ │ ├── unchanged.png │ │ ├── unresponsive.png │ │ └── warning.png │ ├── loading.gif │ └── tipsy.gif └── robots.txt ├── spec ├── controllers │ ├── application_controller_spec.rb │ ├── delayed_job_failures_controller.rb │ ├── files_controller_spec.rb │ ├── node_classes_controller_spec.rb │ ├── node_group_memberships_controller_spec.rb │ ├── node_groups_controller_spec.rb │ ├── nodes_controller_spec.rb │ ├── pages_controller_spec.rb │ └── reports_controller_spec.rb ├── factories.rb ├── fixtures │ ├── reports │ │ ├── failure.yml │ │ ├── formats │ │ │ ├── 00_changes.yaml │ │ │ ├── 01_changes.yaml │ │ │ ├── 02_failing.yaml │ │ │ ├── 03_failing.yaml │ │ │ ├── 04_failing.yaml │ │ │ ├── 05_failing.yaml │ │ │ ├── 06_failing.yaml │ │ │ ├── 07_failing.yaml │ │ │ ├── 08_failing.yaml │ │ │ └── 09_failing.yaml │ │ ├── meta.yml │ │ ├── puppet25 │ │ │ └── 1_changed_0_failures.yml │ │ ├── puppet26 │ │ │ ├── 0_changed_0_failures.yml │ │ │ ├── report_error_exec_returns_non_zero.yaml │ │ │ ├── report_error_missing_dependency.yaml │ │ │ ├── report_error_on_package_service_and_files.yaml │ │ │ ├── report_ok_exec_returns_zero.yaml │ │ │ ├── report_ok_file_service_package.yaml │ │ │ ├── report_ok_service_and_exec_already_in_correct_state.yaml │ │ │ ├── report_ok_service_started_ok.yaml │ │ │ ├── report_ok_single_file.yaml │ │ │ └── resource_status_test.yaml │ │ ├── success.yml │ │ └── version2 │ │ │ └── example.yaml │ ├── sample_report.yml │ ├── sample_report.yml.erb │ └── sample_report_2_6_0.yml ├── helpers │ ├── application_helper_spec.rb │ ├── pages_helper_spec.rb │ ├── paginate_scope_helper_spec.rb │ ├── reports_helper_spec.rb │ ├── status_helper_spec.rb │ └── string_helper_spec.rb ├── lib │ ├── core_callbacks_spec.rb │ ├── puppet │ │ └── report_sanitizer_spec.rb │ ├── registry_spec.rb │ ├── report_transformer_spec.rb │ ├── settings_reader_spec.rb │ └── settings_spec.rb ├── models │ ├── node_class_membership_spec.rb │ ├── node_class_spec.rb │ ├── node_group_class_membership_spec.rb │ ├── node_group_edge_spec.rb │ ├── node_group_membership_spec.rb │ ├── node_group_spec.rb │ ├── node_spec.rb │ ├── parameter_spec.rb │ ├── report_spec.rb │ ├── resource_event_spec.rb │ ├── resource_status_spec.rb │ └── status_spec.rb ├── rcov.opts.example ├── shared_behaviors │ ├── action_integration_behavior.rb │ ├── controller_mixins.rb │ ├── controller_search.rb │ ├── restful_routing_behavior.rb │ └── sorted_index.rb ├── spec.opts.example ├── spec_helper.rb ├── support │ ├── describe_reports.rb │ ├── factory_bot.rb │ ├── from_response_body.rb │ ├── report_support.rb │ ├── response_codes.rb │ └── should_matchers.rb ├── views │ ├── node_classes │ │ ├── _actions.html.haml_spec.rb │ │ ├── edit.html.haml_spec.rb │ │ ├── index.html.haml_spec.rb │ │ ├── new.html.haml_spec.rb │ │ └── show.html.haml_spec.rb │ ├── node_groups │ │ ├── _actions.html.haml_spec.rb │ │ ├── _search.html.haml_spec.rb │ │ ├── edit.html.haml_spec.rb │ │ ├── index.html.haml_spec.rb │ │ ├── new.html.haml_spec.rb │ │ └── show.html.haml_spec.rb │ ├── nodes │ │ ├── edit.html.haml_spec.rb │ │ ├── index.html.haml_spec.rb │ │ ├── new.html.haml_spec.rb │ │ └── show.html.haml_spec.rb │ ├── pages │ │ └── home.html.haml_spec.rb │ ├── reports │ │ ├── _report.html.haml_spec.rb │ │ ├── _report_status_icon.html.haml_spec.rb │ │ ├── _report_status_td.html.haml_spec.rb │ │ ├── index.html.haml_spec.rb │ │ └── show.html.haml_spec.rb │ ├── statuses │ │ └── _run_failure.html.haml_spec.rb │ └── timeline_events │ │ └── _timeline_event.haml_spec.rb └── watchr.rb.example ├── spool └── .gitignore └── tmp └── .gitignore /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile ~/.gitignore_global 6 | 7 | # Ignore your configs 8 | /config/settings.yml 9 | /config/database.yml 10 | 11 | # Ignore bundler config 12 | /.bundle 13 | /vendor/bundle 14 | 15 | # Ignore the default SQLite database 16 | /db/*.sqlite3 17 | 18 | # Ignore all logfiles and tempfiles 19 | /log/*.log 20 | /tmp 21 | 22 | # Ignore asset pipeline output 23 | /public/assets 24 | 25 | # Ignore packaging artifacts 26 | /ext/packaging 27 | /pkg 28 | 29 | # Ignore Ruby selection tools 30 | /.rvmrc 31 | /.rbenv 32 | 33 | # Ignore coverage report results 34 | /coverage 35 | -------------------------------------------------------------------------------- /.haml-lint.yml: -------------------------------------------------------------------------------- 1 | inherits_from: .haml-lint_todo.yml 2 | exclude: 3 | - 'vendor/**/*' 4 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_from: .rubocop_todo.yml 2 | 3 | require: 4 | - rubocop-rails 5 | - rubocop-rspec 6 | - rubocop-performance 7 | 8 | inherit_gem: 9 | rubocop-rails_config: 10 | - config/rails.yml 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | cache: bundler 3 | env: 4 | global: 5 | - CC_TEST_REPORTER_ID=aa9428ecce81885fa4f1c0d0283f0075e353dd1894ececefb103846e32794de3 6 | matrix: 7 | - DB=mysql 8 | - DB=postgres 9 | services: 10 | - mysql 11 | - postgresql 12 | rvm: 13 | - 2.4 14 | - 2.5 15 | - 2.6 16 | - 2.7 17 | before_install: gem install bundler --version '~> 1' 18 | before_script: 19 | - cp config/database.yml.travis config/database.yml 20 | - 'echo "test: *${DB}" >> config/database.yml' 21 | - bundle exec rails db:create 22 | - bundle exec rails db:migrate 23 | - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter 24 | - chmod +x ./cc-test-reporter 25 | - ./cc-test-reporter before-build 26 | script: 27 | - bundle exec rails spec 28 | - bundle exec rubocop 29 | - bundle exec haml-lint 30 | after_script: 31 | - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT 32 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'rdoc' 5 | gem 'rails', '~> 5.2.3' 6 | gem 'will_paginate' 7 | gem 'inherited_resources' 8 | gem 'i18n' 9 | 10 | gem 'thin' 11 | gem 'rack' 12 | gem 'bootsnap' 13 | 14 | gem 'daemons' 15 | gem 'json_pure' 16 | gem 'safe_yaml', :require => false 17 | 18 | gem 'delayed_job' 19 | gem 'delayed_job_active_record' 20 | gem 'timeline_fu' 21 | gem 'haml' 22 | 23 | gem 'sass-rails', '~> 5' 24 | gem 'haml-rails' 25 | gem 'jquery-rails' 26 | gem 'jquery-ui-rails' 27 | gem 'uglifier' 28 | gem 'execjs' 29 | gem 'therubyracer' 30 | 31 | gem 'web-console', group: :development 32 | 33 | gem 'ruby-progressbar' 34 | 35 | group :development, :test do 36 | gem 'mocha' 37 | gem 'sqlite3' 38 | gem 'rspec-rails' 39 | gem 'rspec-html-matchers' 40 | gem 'rspec-collection_matchers' 41 | gem 'shoulda-matchers', '~> 3' 42 | gem 'factory_bot_rails' 43 | gem 'nokogiri' 44 | gem 'rails-controller-testing' 45 | gem 'listen' 46 | gem 'simplecov' 47 | gem 'simplecov-console' 48 | gem 'rubocop' 49 | gem 'rubocop-performance' 50 | gem 'rubocop-rails' 51 | gem 'rubocop-rails_config' 52 | gem 'rubocop-rspec' 53 | gem 'haml_lint', require: false 54 | end 55 | 56 | group :postgresql do 57 | gem 'pg' 58 | end 59 | 60 | group :mysql do 61 | gem 'mysql2' 62 | end 63 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2011 Puppet Labs 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 3.0.1 2 | -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // the compiled file. 9 | // 10 | // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD 11 | // GO AFTER THE REQUIRES BELOW. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require dashboard 16 | //= require jquery-ui 17 | //= require jquery.tokeninput 18 | //= require jquery.form 19 | //= require jquery.placeholders 20 | //= require jquery.ui.combobox 21 | //= require jquery.colorbox 22 | //= require jquery.cookie 23 | //= require jquery.tipsy 24 | //= require search 25 | //= require autorefresh 26 | //= require jquery.jqplot 27 | //= require jqplot.barRenderer 28 | //= require jqplot.categoryAxisRenderer 29 | //= require jqplot.canvasTextRenderer 30 | //= require jqplot.canvasAxisTickRenderer 31 | //= require jqplot.highlighter 32 | //= require application 33 | //= require ajax_helper 34 | //= require validation_response 35 | 36 | -------------------------------------------------------------------------------- /app/assets/javascripts/application.radiator.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.radiator.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // the compiled file. 9 | // 10 | // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD 11 | // GO AFTER THE REQUIRES BELOW. 12 | // 13 | //= require jquery 14 | //= require radiator 15 | -------------------------------------------------------------------------------- /app/assets/javascripts/search.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | $.fn.filterList = function(opt) { 3 | return this.each(function() { 4 | var self = $(this); 5 | self.keyup(function(e) { 6 | var text = self.attr('value'); 7 | var table = self.parents('.table-tools').next('table') 8 | var rows = table.find('tbody tr') 9 | var matches = text == "" ? rows : rows.find('td.name a:contains("'+text+'")').parents('tr'); 10 | rows.hide(); 11 | matches.show(); 12 | table.find('tbody').trigger('restripe'); 13 | }) 14 | }); 15 | }; 16 | 17 | $.fn.autocompleteInspector = function(url) { 18 | var self = this 19 | self.keyup(function(e) { 20 | var text = $(this).attr('value'); 21 | var div = self.parents('.table-tools').next('.results'); 22 | var html = $.get(url, { q: text }, function(html, status) { 23 | div.html(html); 24 | }, "html"); 25 | }); 26 | return self; 27 | } 28 | })(jQuery); 29 | -------------------------------------------------------------------------------- /app/assets/javascripts/validation_response.js: -------------------------------------------------------------------------------- 1 | function form_submit_success(jsonResponse, error_messages_element_id) { 2 | if(jsonResponse.status == "error") { 3 | errorMessagesElement = document.getElementById(error_messages_element_id); 4 | errorMessagesElement.style.display = "block"; 5 | errorMessagesElement.innerHTML = jsonResponse.error_html; 6 | } 7 | else { 8 | if(jsonResponse.valid == "true") { 9 | window.location = jsonResponse.redirect_to; 10 | } 11 | else { 12 | confirmElement = document.createElement('div'); 13 | confirmElement.style.position = 'absolute'; 14 | confirmElement.style.top = '0px'; 15 | confirmElement.style.right = '0px'; 16 | confirmElement.style.bottom = '0px'; 17 | confirmElement.style.left = '0px'; 18 | document.getElementsByTagName('body')[0].appendChild(confirmElement); 19 | confirmElement.innerHTML = jsonResponse.confirm_html; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the top of the 9 | * compiled file, but it's generally better to create a new file per style scope. 10 | * 11 | *= require_self 12 | *= require_tree . 13 | *= require dashboard 14 | *= require reset 15 | *= require layout 16 | *= require forms 17 | *= require tables 18 | *= require jquery.ui.custom 19 | *= require jquery.ui.combobox 20 | *= require typography 21 | *= require links 22 | *= require token-input-facebook 23 | *= require tipsy 24 | *= require colorbox 25 | *= require help 26 | *= require jquery.jqplot 27 | *= require popups 28 | */ 29 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.radiator.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.radiator.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-radiator related styles to this file and they'll appear at the top of the 9 | * compiled file, but it's generally better to create a new file per style scope. 10 | * 11 | *= require reset 12 | *= require mixins 13 | *= require radiator 14 | */ 15 | -------------------------------------------------------------------------------- /app/assets/stylesheets/help.scss: -------------------------------------------------------------------------------- 1 | .with-help { 2 | position : relative; /* won't someone think of the children? */ 3 | } 4 | .help { 5 | position : absolute; 6 | top : 2px; 7 | right : 4px; 8 | a { 9 | text-indent : -9999px; 10 | background : transparent url( '../images/icons/help.png' ) no-repeat 0% 50%; 11 | cursor : pointer; 12 | width : 16px; 13 | height : 16px; 14 | display : block; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/assets/stylesheets/images/border.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/border.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/controls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/controls.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/grid.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/header.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/icons/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/icons/add.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/icons/add_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/icons/add_grey.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/icons/add_light_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/icons/add_light_grey.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/icons/computer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/icons/computer.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/icons/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/icons/delete.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/icons/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/icons/edit.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/icons/failure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/icons/failure.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/icons/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/icons/search.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/icons/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/icons/success.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/internet_explorer/borderBottomCenter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/internet_explorer/borderBottomCenter.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/internet_explorer/borderBottomLeft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/internet_explorer/borderBottomLeft.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/internet_explorer/borderBottomRight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/internet_explorer/borderBottomRight.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/internet_explorer/borderMiddleLeft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/internet_explorer/borderMiddleLeft.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/internet_explorer/borderMiddleRight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/internet_explorer/borderMiddleRight.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/internet_explorer/borderTopCenter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/internet_explorer/borderTopCenter.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/internet_explorer/borderTopLeft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/internet_explorer/borderTopLeft.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/internet_explorer/borderTopRight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/internet_explorer/borderTopRight.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/loading.gif -------------------------------------------------------------------------------- /app/assets/stylesheets/images/loading_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/loading_background.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/overlay.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/ui-bg_flat_0_eeeeee_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/ui-bg_flat_0_eeeeee_40x100.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/ui-bg_flat_100_5c80a8_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/ui-bg_flat_100_5c80a8_40x100.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/ui-bg_flat_55_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/ui-bg_flat_55_ffffff_40x100.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/ui-bg_flat_65_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/ui-bg_flat_65_ffffff_40x100.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/ui-bg_highlight-soft_100_f6f6f6_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/ui-bg_highlight-soft_100_f6f6f6_1x100.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/ui-bg_highlight-soft_25_0073ea_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/ui-bg_highlight-soft_25_0073ea_1x100.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/ui-bg_highlight-soft_50_dddddd_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/ui-bg_highlight-soft_50_dddddd_1x100.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/ui-icons_0073ea_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/ui-icons_0073ea_256x240.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/ui-icons_666666_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/ui-icons_666666_256x240.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/ui-icons_ff0084_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/ui-icons_ff0084_256x240.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/white-overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/white-overlay.png -------------------------------------------------------------------------------- /app/assets/stylesheets/images/white-overlays.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/assets/stylesheets/images/white-overlays.png -------------------------------------------------------------------------------- /app/assets/stylesheets/jquery.ui.combobox.css: -------------------------------------------------------------------------------- 1 | .ui-button { margin-left: -1px; } 2 | .ui-button-icon-only .ui-button-text { padding: 0.35em; } 3 | .ui-autocomplete-input { margin: 0; padding: 0.48em 0 0.47em 0.45em; } 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/layout.css: -------------------------------------------------------------------------------- 1 | #wrap { 2 | margin: 0 1em 1em; 3 | } 4 | 5 | #skiptargetholder { 6 | position: absolute; 7 | left: -200%; 8 | } 9 | 10 | #header { 11 | margin-bottom: 1em; 12 | } 13 | 14 | #content #sidebar { width: 20%; float: left; clear: left; } 15 | 16 | body.with-sidebar #content #main { width: 80%; float: left; } 17 | body.no-sidebar #content #main { width: 100%; } 18 | 19 | #content #main.full { width: 100%; } 20 | 21 | #content #main #list { 22 | max-height: 300px; 23 | overflow: auto; 24 | } 25 | #content #main #item { 26 | background: #FFF; 27 | } 28 | -------------------------------------------------------------------------------- /app/assets/stylesheets/links.css: -------------------------------------------------------------------------------- 1 | ul.actions { 2 | position: absolute; 3 | right: 1px; 4 | top: 1px; 5 | } 6 | 7 | ul.actions li { 8 | display: inline-block; 9 | } 10 | 11 | a.cancel { 12 | color: #888; 13 | } 14 | .icon { 15 | display: inline-block; 16 | height: 100%; 17 | width: 16px; 18 | text-indent: -9999px; 19 | vertical-align: baseline; 20 | } 21 | 22 | a.icon span { display: none; } 23 | 24 | .icon.success { 25 | background: url(images/icons/success.png) transparent center center no-repeat; 26 | } 27 | 28 | .icon.failed { 29 | background: url(images/icons/failure.png) transparent center center no-repeat; 30 | } 31 | 32 | .icon.add { 33 | background: url(images/icons/add.png) transparent center center no-repeat; 34 | } 35 | 36 | .icon.delete { 37 | background: url(images/icons/delete.png) transparent center center no-repeat; 38 | } 39 | 40 | span.type { 41 | top: 0.25em; 42 | left: 0; 43 | position: absolute; 44 | display: block; 45 | width: 16px; 46 | height: 16px; 47 | } 48 | 49 | span.type span { 50 | display: none; 51 | } 52 | 53 | span.node.type { 54 | background: url(images/icons/computer.png); 55 | } 56 | -------------------------------------------------------------------------------- /app/assets/stylesheets/mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin node_summary_row($color) { 2 | a { 3 | color : $color; 4 | } 5 | .percent { 6 | a { 7 | background-color : $color; 8 | } 9 | } 10 | &.hover, 11 | &.active, 12 | &:hover { 13 | background-color : $color; 14 | a { 15 | color : #fff; 16 | text-decoration : none; 17 | } 18 | .percent { 19 | a { 20 | background-color : #fff; 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/assets/stylesheets/popups.css: -------------------------------------------------------------------------------- 1 | #popupWindowGlass, #popupWindowLayoutHelperTable { 2 | position: absolute; 3 | top: 0; 4 | bottom: 0; 5 | left: 0; 6 | right: 0; 7 | } 8 | 9 | #popupWindowGlass { 10 | background-color: black; 11 | opacity: 0.4; 12 | } 13 | 14 | #popupWindowLayoutHelperTable { 15 | display: table; 16 | width: 100%; 17 | height: 100%; 18 | } 19 | 20 | #popupWindowLayoutHelperTableCell { 21 | display: table-cell; 22 | text-align: center; 23 | vertical-align: middle; 24 | } 25 | 26 | #popupWindow { 27 | background-color: white; 28 | display: inline-block; 29 | padding: 20px; 30 | border: 1px solid #aaa; 31 | border-radius: 4px; 32 | text-align: left; 33 | } 34 | 35 | #popupWindowButtons { 36 | margin-top: 20px; 37 | } -------------------------------------------------------------------------------- /app/assets/stylesheets/reset.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { 2 | margin: 0; 3 | padding: 0; 4 | border: 0; 5 | font-weight: inherit; 6 | font-style: inherit; 7 | font-size: 100%; 8 | font-family: inherit; 9 | vertical-align: baseline; 10 | } 11 | 12 | body { 13 | line-height: 20px; 14 | } 15 | 16 | table { 17 | border-collapse: separate; 18 | border-spacing: 0; 19 | } 20 | 21 | caption, th, td { 22 | text-align: left; 23 | font-weight: normal; 24 | } 25 | 26 | table, td, th { 27 | vertical-align: middle; 28 | } 29 | 30 | blockquote:before, blockquote:after, q:before, q:after { 31 | content: ""; 32 | } 33 | 34 | blockquote, q { 35 | quotes: "" ""; 36 | } 37 | 38 | a img { 39 | border: none; 40 | } 41 | 42 | ul { 43 | list-style-position: inside; 44 | } 45 | 46 | -------------------------------------------------------------------------------- /app/assets/stylesheets/tipsy.css: -------------------------------------------------------------------------------- 1 | .tipsy { padding: 5px; font-size: 12px; position: absolute; z-index: 100000; } 2 | .tipsy-inner { padding: 5px 8px 4px 8px; background-color: black; color: white; max-width: 200px; text-align: center; } 3 | .tipsy-inner { border-radius: 3px; -moz-border-radius:3px; -webkit-border-radius:3px; } 4 | .tipsy-arrow { position: absolute; background: url('../images/tipsy.gif') no-repeat top left; width: 9px; height: 5px; } 5 | .tipsy-n .tipsy-arrow { top: 0; left: 50%; margin-left: -4px; } 6 | .tipsy-nw .tipsy-arrow { top: 0; left: 10px; } 7 | .tipsy-ne .tipsy-arrow { top: 0; right: 10px; } 8 | .tipsy-s .tipsy-arrow { bottom: 0; left: 50%; margin-left: -4px; background-position: bottom left; } 9 | .tipsy-sw .tipsy-arrow { bottom: 0; left: 10px; background-position: bottom left; } 10 | .tipsy-se .tipsy-arrow { bottom: 0; right: 10px; background-position: bottom left; } 11 | .tipsy-e .tipsy-arrow { top: 50%; margin-top: -4px; right: 0; width: 5px; height: 9px; background-position: top right; } 12 | .tipsy-w .tipsy-arrow { top: 50%; margin-top: -4px; left: 0; width: 5px; height: 9px; } 13 | -------------------------------------------------------------------------------- /app/controllers/delayed_job_failures_controller.rb: -------------------------------------------------------------------------------- 1 | class DelayedJobFailuresController < ApplicationController 2 | def index 3 | @read = false 4 | @delayed_job_failures = get_failures(@read) 5 | end 6 | 7 | def read_all 8 | DelayedJobFailure.transaction do 9 | # Can't just update_all, because this is a WillPaginate collection, 10 | # and it has a limited API. Alas. --daniel 2011-06-20 11 | DelayedJobFailure.all.each do |event| 12 | event.read = true 13 | event.save! 14 | end 15 | end 16 | @delayed_job_failures = [] 17 | 18 | redirect_to "/" 19 | end 20 | 21 | def read 22 | @read = true 23 | @delayed_job_failures = get_failures(true) 24 | render 'delayed_job_failures/index' 25 | end 26 | 27 | protected 28 | def get_failures(read) 29 | respond_to do |format| 30 | format.html do 31 | paginate_scope(DelayedJobFailure.where(:read => read).order('created_at DESC')) 32 | end 33 | 34 | format.all do 35 | DelayedJobFailure.where(:read => read).order('created_at DESC') 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /app/controllers/help_controller.rb: -------------------------------------------------------------------------------- 1 | class HelpController < ApplicationController 2 | def node_status 3 | respond_to do |format| 4 | format.html { render(partial: 'node_status') } 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/controllers/node_class_memberships_controller.rb: -------------------------------------------------------------------------------- 1 | class NodeClassMembershipsController < InheritedResources::Base 2 | respond_to :html, :json 3 | before_action :raise_unless_using_external_node_classification 4 | before_action :raise_if_enable_read_only_mode, :only => [:new, :edit, :create, :update, :destroy] 5 | 6 | include SearchableIndex 7 | include ConflictAnalyzer 8 | include ConflictHtml 9 | 10 | def update 11 | update_helper :class => NodeClassMembership, 12 | :conflict_attribute => :node 13 | end 14 | 15 | def destroy 16 | destroy_helper :class => NodeClassMembership, 17 | :owner_class => Node, 18 | :conflict_attribute => :node 19 | end 20 | 21 | end 22 | -------------------------------------------------------------------------------- /app/controllers/node_classes_controller.rb: -------------------------------------------------------------------------------- 1 | class NodeClassesController < InheritedResources::Base 2 | respond_to :html, :json, :yaml 3 | before_action :raise_unless_using_external_node_classification 4 | before_action :raise_if_enable_read_only_mode, :only => [:new, :edit, :create, :update, :destroy] 5 | 6 | include SearchableIndex 7 | 8 | protected 9 | 10 | def node_class_params 11 | params.require(:node_class).permit(:name, :description) 12 | end 13 | 14 | def resource 15 | get_resource_ivar || set_resource_ivar(end_of_association_chain.find_by_id_or_name!(params[:id])) 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/controllers/node_group_class_memberships_controller.rb: -------------------------------------------------------------------------------- 1 | class NodeGroupClassMembershipsController < InheritedResources::Base 2 | respond_to :html, :json 3 | before_action :raise_unless_using_external_node_classification 4 | before_action :raise_if_enable_read_only_mode, :only => [:new, :edit, :create, :update, :destroy] 5 | 6 | include SearchableIndex 7 | include ConflictAnalyzer 8 | include ConflictHtml 9 | 10 | def update 11 | update_helper :class => NodeGroupClassMembership, 12 | :conflict_attribute => :node_group 13 | end 14 | 15 | def destroy 16 | destroy_helper :class => NodeGroupClassMembership, 17 | :owner_class => NodeGroup, 18 | :conflict_attribute => :node_group 19 | end 20 | 21 | end 22 | -------------------------------------------------------------------------------- /app/controllers/node_group_memberships_controller.rb: -------------------------------------------------------------------------------- 1 | class NodeGroupMembershipsController < InheritedResources::Base 2 | respond_to :json 3 | before_action :raise_if_enable_read_only_mode, :only => [:new, :edit, :create, :update, :destroy] 4 | before_action :standardize_post_data, :only => [:create] 5 | 6 | def create 7 | create!(node_group_membership_params) do |success, failure| 8 | success.json { render :json => @node_group_membership, :status => 201 } 9 | failure.json { render :json => {}, :status => 422 } 10 | end 11 | end 12 | 13 | # we want: {node_group_membership => {node_id => , node_group_id => } 14 | # allow and convert: {node_name => , group_name => } 15 | def standardize_post_data 16 | unless params[:node_group_membership] 17 | conv = params.permit(:node_name, :group_name) 18 | node = Node.find_by_name(conv[:node_name]) 19 | group = NodeGroup.find_by_name(conv[:group_name]) 20 | params[:node_group_membership] = {} 21 | params[:node_group_membership][:node_id] = (node && node.id) 22 | params[:node_group_membership][:node_group_id] = (group && group.id) 23 | end 24 | end 25 | 26 | def node_group_membership_params 27 | params.require(:node_group_membership).permit(:node_id, :node_group_id) 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /app/controllers/pages_controller.rb: -------------------------------------------------------------------------------- 1 | class PagesController < ApplicationController 2 | def home 3 | @all_nodes = Node.unhidden.by_report_date 4 | 5 | @unreported_nodes = @all_nodes.unreported 6 | @unresponsive_nodes = @all_nodes.unresponsive 7 | @failed_nodes = @all_nodes.failed 8 | @pending_nodes = @all_nodes.pending 9 | @changed_nodes = @all_nodes.changed 10 | @unchanged_nodes = @all_nodes.unchanged 11 | end 12 | 13 | def header 14 | respond_to do |format| 15 | format.html { render :partial => 'shared/global_nav' } 16 | end 17 | end 18 | 19 | end 20 | -------------------------------------------------------------------------------- /app/controllers/radiator_controller.rb: -------------------------------------------------------------------------------- 1 | class RadiatorController < InheritedResources::Base 2 | respond_to :html, :json 3 | 4 | def index 5 | @node_summary = { 'display' => [] } 6 | 7 | # Get the primary statuses in one query 8 | @node_summary.merge!(Node.count_by_status) 9 | 10 | # Continue the loop to pick up other radiator statuses 11 | Node.radiator_statuses.each do |status| 12 | case status 13 | when 'all' 14 | @node_summary['display'] << { 'key' => 'all', 'name' => 'Total' } 15 | @node_summary[status] = Node.unhidden.count 16 | else 17 | @node_summary['display'] << { 'key' => status, 'name' => status.capitalize } 18 | @node_summary[status] = @node_summary[status] || Node.send(status).unhidden.count 19 | end 20 | end 21 | 22 | respond_to do |format| 23 | format.html { render :partial => 'shared/node_summary', :layout => 'radiator' } 24 | format.json { render :json => @node_summary } 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /app/helpers/node_classes_helper.rb: -------------------------------------------------------------------------------- 1 | module NodeClassesHelper 2 | def node_classes 3 | NodeClass.all 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/helpers/node_groups_helper.rb: -------------------------------------------------------------------------------- 1 | module NodeGroupsHelper 2 | def node_groups 3 | @node_groups ||= NodeGroup.all 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/helpers/nodes_helper.rb: -------------------------------------------------------------------------------- 1 | module NodesHelper 2 | def nodes 3 | return parent.nodes if parent? 4 | collection || @nodes || Node.all 5 | end 6 | 7 | def node_title_text(node) 8 | return "No reports" unless node.status 9 | node.status.titleize.tap do |str| 10 | str << " " << time_ago_in_words(node.reported_at) << " ago" if node.reported_at 11 | end 12 | end 13 | 14 | def report_title_text(report) 15 | report.status.titleize.tap do |str| 16 | str << " " << time_ago_in_words(report.time) << " ago" 17 | end 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /app/helpers/pages_helper.rb: -------------------------------------------------------------------------------- 1 | module PagesHelper 2 | def percentage(node_count, all_node_count) 3 | return 0 unless all_node_count > 0 4 | (100 * node_count / all_node_count.to_f).round(1) 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/helpers/paginate_scope_helper.rb: -------------------------------------------------------------------------------- 1 | require 'will_paginate/array' 2 | 3 | module PaginateScopeHelper 4 | # Return a paginated +scope+. 5 | def paginate_scope(scope, opts={}) 6 | if ! params[:per_page] 7 | per_page = scope.first.class.per_page rescue nil 8 | page = params[:page] 9 | elsif params[:per_page] == 'all' 10 | per_page = scope.count 11 | page = 1 12 | else 13 | per_page = params[:per_page] 14 | page = begin 15 | if per_page.to_i * params[:page].to_i > scope.count 16 | scope.count / per_page.to_i + 1 # last page 17 | else 18 | params[:page] 19 | end 20 | rescue StandardError 21 | params[:page] 22 | end 23 | end 24 | 25 | # Handle negative / invalid page numbers gracefully 26 | page = (page.to_i > 0 ? page : 1) rescue 1 27 | per_page = (per_page.to_i > 0 ? per_page : nil) rescue nil 28 | 29 | scope.paginate( opts.reverse_merge(:page => page, :per_page => per_page) ) 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /app/helpers/reports_helper.rb: -------------------------------------------------------------------------------- 1 | module ReportsHelper 2 | def popup_md5s( string, options = {} ) 3 | if SETTINGS.use_file_bucket_diffs 4 | string.gsub(/\{md5\}[a-fA-F0-9]{32}/) do |match| 5 | if options[:exclude_md5s] and options[:exclude_md5s].include? match 6 | match 7 | else 8 | popup_url = url_for :controller => :files, :action => :show, :file => match.sub('{md5}','') 9 | link_to options[:label] || match, '#', :onclick => "display_file_popup('#{popup_url}'); return false;", :class => 'popup-md5' 10 | end 11 | end 12 | else 13 | string 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/helpers/status_helper.rb: -------------------------------------------------------------------------------- 1 | module StatusHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/string_helper.rb: -------------------------------------------------------------------------------- 1 | module StringHelper 2 | private 3 | def is_md5?(str) 4 | !!(str =~ /^[0-9a-f]{32}$/) 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/mailers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/mailers/.gitkeep -------------------------------------------------------------------------------- /app/mixins/searchable_index.rb: -------------------------------------------------------------------------------- 1 | module SearchableIndex 2 | private 3 | 4 | def collection 5 | coll = end_of_association_chain.search(params[:q] || params[:tag]) 6 | coll = paginate_scope(coll) if request.format == :html 7 | 8 | get_collection_ivar || set_collection_ivar(coll) 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/models/.gitkeep -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /app/models/delayed_job_failure.rb: -------------------------------------------------------------------------------- 1 | class DelayedJobFailure < ApplicationRecord 2 | def self.per_page; 25 end 3 | 4 | scope :unread, -> { where(:read => false) } 5 | serialize :backtrace 6 | end 7 | -------------------------------------------------------------------------------- /app/models/metric.rb: -------------------------------------------------------------------------------- 1 | class Metric < ApplicationRecord 2 | belongs_to :report 3 | end 4 | -------------------------------------------------------------------------------- /app/models/node_class_membership.rb: -------------------------------------------------------------------------------- 1 | class NodeClassMembership < ApplicationRecord 2 | validates_presence_of :node_id, :node_class_id 3 | 4 | include NodeGroupGraph 5 | 6 | has_parameters 7 | 8 | belongs_to :node 9 | belongs_to :node_class 10 | 11 | fires :added_to, :on => :create, :subject => :node_class, :secondary_subject => :node 12 | fires :removed_from, :on => :destroy, :subject => :node_class, :secondary_subject => :node 13 | end 14 | -------------------------------------------------------------------------------- /app/models/node_group_class_membership.rb: -------------------------------------------------------------------------------- 1 | class NodeGroupClassMembership < ApplicationRecord 2 | include NodeGroupGraph 3 | 4 | has_parameters 5 | 6 | belongs_to :node_class, required: true 7 | belongs_to :node_group, required: true 8 | end 9 | -------------------------------------------------------------------------------- /app/models/node_group_edge.rb: -------------------------------------------------------------------------------- 1 | class NodeGroupEdge < ApplicationRecord 2 | belongs_to :to, :class_name => 'NodeGroup' 3 | belongs_to :from, :class_name => 'NodeGroup' 4 | 5 | validate :validate_dag 6 | 7 | # Performs a depth-first search on all graphs containing this edge, 8 | # reporting an error and failing validation if there is a loop. Keeps 9 | # a list of encountered nodes and fails if it encounters the same group 10 | # twice. 11 | def validate_dag 12 | def dfs(group, seen) 13 | if seen.include?(group) 14 | self.errors[:base] << ( 15 | "Creating a dependency from group '#{from.name}' to " \ 16 | + (from.name == to.name ? "itself" : "group '#{to.name}'") \ 17 | + " creates a cycle") 18 | end 19 | group.node_groups.each { |grp| 20 | dfs(grp, seen + [group]) 21 | } 22 | end 23 | 24 | dfs(self.to,[self.from]) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /app/models/node_group_membership.rb: -------------------------------------------------------------------------------- 1 | class NodeGroupMembership < ApplicationRecord 2 | validates_uniqueness_of :node_id, :scope => :node_group_id 3 | 4 | belongs_to :node, required: true 5 | belongs_to :node_group, required: true 6 | 7 | def to_json(*args) 8 | {"node_group_id" => node_group_id, "node_id" => node_id}.to_json(*args) 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/models/parameter.rb: -------------------------------------------------------------------------------- 1 | class Parameter < ApplicationRecord 2 | include Trimmer 3 | trimmed_fields :key 4 | 5 | belongs_to :parameterable, polymorphic: true, optional: true 6 | validates_presence_of :key 7 | 8 | serialize :value 9 | 10 | fires :added_to, :on => :create, :secondary_subject => 'parameterable' 11 | fires :removed_from, :on => :destroy, :secondary_subject => 'parameterable' 12 | fires :changed_on, :on => :update, :secondary_subject => 'parameterable' 13 | 14 | def name 15 | "Parameter '#{key}'" 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/models/report_log.rb: -------------------------------------------------------------------------------- 1 | class ReportLog < ApplicationRecord 2 | belongs_to :report 3 | 4 | serialize :tags, Array 5 | end 6 | -------------------------------------------------------------------------------- /app/models/resource_event.rb: -------------------------------------------------------------------------------- 1 | class ResourceEvent < ApplicationRecord 2 | belongs_to :resource_status 3 | 4 | # Only perform YAMLization on non-strings. 5 | class ValueWrapper 6 | def self.load(val) 7 | begin 8 | if val.start_with?('---') 9 | YAML.load(val) 10 | else 11 | val 12 | end 13 | rescue StandardError 14 | val 15 | end 16 | end 17 | 18 | def self.dump(val) 19 | val.is_a?(String) ? val : YAML.dump(val) 20 | end 21 | end 22 | 23 | serialize :desired_value, ValueWrapper 24 | serialize :previous_value, ValueWrapper 25 | serialize :historical_value, ValueWrapper 26 | 27 | # The "natural" order of properties is that 'ensure' comes before anything 28 | # else, then alphabetically sorted by the property name. 29 | def <=>(that) 30 | [self.property == 'ensure' ? 0 : 1, self.property] <=> 31 | [that.property == 'ensure' ? 0 : 1, that.property] 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /app/models/timeline_event.rb: -------------------------------------------------------------------------------- 1 | class TimelineEvent < ApplicationRecord 2 | belongs_to :actor, polymorphic: true, optional: true 3 | belongs_to :subject, polymorphic: true, optional: true 4 | belongs_to :secondary_subject, polymorphic: true, optional: true 5 | 6 | scope :for_node, ->(node) do 7 | where(<<-SQL, {:id => node.id, :klass => node.class.name}) 8 | (subject_id = :id AND subject_type = :klass) OR 9 | (secondary_subject_id = :id AND secondary_subject_type = :klass) 10 | SQL 11 | end 12 | scope :recent, ->(n = 10) { order('created_at DESC, id DESC').limit(n) } 13 | 14 | def subject_name 15 | subject ? subject.name : "A #{subject_type.downcase}" 16 | end 17 | 18 | def secondary_name 19 | secondary_subject ? secondary_subject.name : "a #{secondary_subject_type.underscore.humanize.downcase}" 20 | end 21 | 22 | def object_type 23 | (secondary_subject_type || subject_type).to_s.downcase 24 | end 25 | 26 | def action 27 | "was #{event_type.tr('_', ' ')}" 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /app/views/layouts/_radiator.html.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %head 4 | - page_title = yield(:page_title) 5 | %title= 'Puppet Node Manager' 6 | %meta{"http-equiv" => "refresh", :content => 30.minutes} 7 | = stylesheet_link_tag 'application.radiator' 8 | = javascript_include_tag 'application.radiator' 9 | 10 | - add_body_class "#{controller.controller_name}_controller" 11 | - add_body_class "#{controller.controller_name}_#{controller.action_name}_action" 12 | - add_body_class "#{controller.controller_name}_form_action" if %w[new create edit update].include?(controller.action_name) 13 | - add_body_class "no-sidebar" unless @body_classes.include?('with-sidebar') 14 | %body{:class => @body_classes} 15 | = yield 16 | -------------------------------------------------------------------------------- /app/views/metrics/_metrics_table.html.haml: -------------------------------------------------------------------------------- 1 | - metrics = local_assigns[:metrics] 2 | - values, total = metrics.partition{|metric| metric.name != "total"} 3 | - values = values.sort_by(&:name) 4 | - values.concat(total) 5 | %tbody 6 | - values.each do |metric| 7 | %tr 8 | %td.key{:class => metric.name}= metric.name.titleize 9 | %td.value{:class => metric.name} 10 | - if metric.category == "time" 11 | = "%0.2f" % metric.value.to_f 12 | seconds 13 | - else 14 | = metric.value.to_i 15 | -------------------------------------------------------------------------------- /app/views/node_class_memberships/_form.html.haml: -------------------------------------------------------------------------------- 1 | = header_for(form) 2 | 3 | .item 4 | .section 5 | #error_messages{:style => "display: none;"} 6 | 7 | %h3 Assigned To Node: 8 | = link_to @node.name, node_path(@node) 9 | 10 | .section 11 | .element 12 | = render :partial => 'parameters/parameter_input', :object => form.object.parameters 13 | -------------------------------------------------------------------------------- /app/views/node_class_memberships/edit.html.haml: -------------------------------------------------------------------------------- 1 | #sidebar= render 'shared/node_manager_sidebar' 2 | #main 3 | - @node_class_memberhip = NodeClassMembership.find_by_id(params[:id]) 4 | - @node_class_id = @node_class_membership.node_class_id 5 | - @node_class = NodeClass.find_by_id(@node_class_id) 6 | - @node_id = @node_class_membership.node_id 7 | - @node = Node.find_by_id(@node_id) 8 | 9 | = form_for @node_class_membership, :url => url_for(@node_class_membership), :html => {:id => "param_form"} do |f| 10 | %input{:id => "force_update", :name => "force_update", :type => "hidden", :value => "false"} 11 | = render f 12 | .element.actions 13 | %button{:id => "submit_button"} Update 14 | or go to 15 | = link_to @node.name, "/nodes/#{@node_id}" 16 | %script{:type=>"text/javascript"} 17 | register_ajax_submit("#param_form"); 18 | -------------------------------------------------------------------------------- /app/views/node_classes/_actions.html.haml: -------------------------------------------------------------------------------- 1 | %ul 2 | %li 3 | = link_to "Add class", new_node_class_path, :class => 'button' 4 | -------------------------------------------------------------------------------- /app/views/node_classes/_form.html.haml: -------------------------------------------------------------------------------- 1 | = focus :node_class_name 2 | 3 | = header_for(form) 4 | 5 | .item 6 | = render :partial => 'shared/form_errors', :object => form.object.errors 7 | 8 | .element 9 | = form.label :name 10 | = form.text_field :name, :placeholder => "Class name" 11 | 12 | .element.textarea 13 | = form.label :description 14 | = form.text_area :description, :rows => 4, :placeholder => "Enter a description for this class here..." 15 | -------------------------------------------------------------------------------- /app/views/node_classes/edit.html.haml: -------------------------------------------------------------------------------- 1 | #sidebar= render :partial => 'shared/node_manager_sidebar' 2 | #main 3 | = form_for @node_class, :url => node_class_path(@node_class.id) do |f| 4 | = render f 5 | .element.actions 6 | %button Update 7 | or 8 | = link_to 'Cancel', @node_class 9 | -------------------------------------------------------------------------------- /app/views/node_classes/index.html.haml: -------------------------------------------------------------------------------- 1 | #sidebar= render 'shared/node_manager_sidebar' 2 | #main 3 | .header 4 | %h2.half 5 | Classes 6 | = describe_search_if_present 7 | = render 'shared/search' if action_name == "index" 8 | %br.clear 9 | 10 | .item 11 | - if @node_classes.present? 12 | %table.main 13 | %thead 14 | %tr 15 | %th.name{:style => 'width: 33%;'} 16 | Name 17 | %th.description 18 | Description 19 | %tbody 20 | - for node_class in @node_classes 21 | %tr[node_class] 22 | %td.name 23 | = link_to h(node_class.name), node_class 24 | %td.description 25 | = node_class.description 26 | %tfoot 27 | %tr 28 | %td{:colspan => 2} 29 | = pagination_for @node_classes 30 | - else 31 | %p 32 | = describe_no_matches_for :classes 33 | 34 | %br.clear 35 | -------------------------------------------------------------------------------- /app/views/node_classes/new.html.haml: -------------------------------------------------------------------------------- 1 | #sidebar= render 'shared/node_manager_sidebar' 2 | #main 3 | = form_for(@node_class) do |f| 4 | = render f 5 | .element.actions 6 | %button Create 7 | or 8 | = link_to 'Cancel', node_classes_path 9 | -------------------------------------------------------------------------------- /app/views/node_group_class_memberships/_form.html.haml: -------------------------------------------------------------------------------- 1 | = header_for(form) 2 | 3 | .item 4 | .section 5 | #error_messages{:style => "display: none;"} 6 | 7 | %h3 Assigned To Node Group: 8 | = link_to @node_group.name, node_group_path(@node_group) 9 | 10 | .section 11 | .element 12 | = render :partial => 'parameters/parameter_input', :object => form.object.parameters 13 | -------------------------------------------------------------------------------- /app/views/node_group_class_memberships/edit.html.haml: -------------------------------------------------------------------------------- 1 | #sidebar= render 'shared/node_manager_sidebar' 2 | #main 3 | - @node_class_id = @node_group_class_membership.node_class_id 4 | - @node_class = NodeClass.find_by_id(@node_class_id) 5 | - @node_group_id = @node_group_class_membership.node_group_id 6 | - @node_group = NodeGroup.find_by_id(@node_group_id) 7 | 8 | = form_for(@node_group_class_membership, :url => url_for(@node_group_class_membership), :html => {:id => "param_form"}) do |f| 9 | %input{:id => "force_update", :name => "force_update", :type => "hidden", :value => "false"} 10 | = render f 11 | .element.actions 12 | %button{:id => "submit_button"} Update 13 | or go to 14 | = link_to @node_group.name, node_group_path(@node_group) 15 | %script{:type=>"text/javascript"} 16 | register_ajax_submit("#param_form"); 17 | -------------------------------------------------------------------------------- /app/views/node_groups/_actions.html.haml: -------------------------------------------------------------------------------- 1 | %ul 2 | %li 3 | = link_to "Add group", new_node_group_path, :class => 'button' 4 | -------------------------------------------------------------------------------- /app/views/node_groups/_form.html.haml: -------------------------------------------------------------------------------- 1 | = focus :node_group_name 2 | 3 | = header_for(form) 4 | 5 | .item 6 | = render :partial => 'shared/form_errors', :object => form.object.errors 7 | 8 | .element 9 | = form.label :name 10 | = form.text_field :name, :placeholder => "Group name" 11 | 12 | .element.textarea 13 | = form.label :description 14 | = form.text_area :description, :rows => 4, :placeholder => "Enter a description for this group here..." 15 | 16 | - if SETTINGS.use_external_node_classification 17 | .element 18 | = render :partial => 'parameters/parameter_input', :object => form.object.parameters, :locals => { :entity_name => 'variable' } 19 | 20 | = render :partial => 'shared/tokenized_text_box', 21 | :locals => { :model => 'node_class', :title => 'Classes', :source => 'node_group' } 22 | 23 | - {'node_group' => 'Groups', 'node' => 'Nodes'}.each do |model, title| 24 | = render :partial => 'shared/tokenized_text_box', 25 | :locals => { :model => model, :title => title, :source => 'node_group' } 26 | 27 | %script#tokenizer{:type => "text/javascript"}= tokenize_input_class(@class_data, @group_data, @node_data) 28 | -------------------------------------------------------------------------------- /app/views/node_groups/_search.html.haml: -------------------------------------------------------------------------------- 1 | = form_tag request.url, :class => 'search' do 2 | = text_field_tag 'q' 3 | %button Search 4 | -------------------------------------------------------------------------------- /app/views/node_groups/edit.html.haml: -------------------------------------------------------------------------------- 1 | #sidebar= render 'shared/node_manager_sidebar' 2 | #main 3 | = form_for @node_group, :url => node_group_path(@node_group.id), :html => {:id => "param_form"} do |f| 4 | %input{:id => "force_update", :name => "force_update", :type => "hidden", :value => "false"} 5 | = render f 6 | .element.actions 7 | %button{:id => "submit_button"} Update 8 | or 9 | = link_to 'Cancel', @node_group 10 | %script{:type=>"text/javascript"} 11 | register_ajax_submit("#param_form"); 12 | -------------------------------------------------------------------------------- /app/views/node_groups/index.html.haml: -------------------------------------------------------------------------------- 1 | #sidebar= render 'shared/node_manager_sidebar' 2 | #main 3 | .header 4 | %h2.half 5 | Groups 6 | = describe_search_if_present 7 | = render 'shared/search' if action_name == "index" 8 | %br.clear 9 | 10 | .item 11 | - if @node_groups.present? 12 | %table.main 13 | %thead 14 | %tr 15 | %th.name{:style => 'width: 33%;'} 16 | Name 17 | %th.description 18 | Description 19 | %tbody 20 | - for node_group in @node_groups 21 | %tr[node_group] 22 | %td.name 23 | = link_to h(node_group.name), node_group 24 | %td.description 25 | = node_group.description 26 | %tfoot 27 | %tr 28 | %td{:colspan => 2} 29 | = pagination_for @node_groups 30 | - else 31 | %p 32 | = describe_no_matches_for :groups 33 | 34 | %br.clear 35 | -------------------------------------------------------------------------------- /app/views/node_groups/new.html.haml: -------------------------------------------------------------------------------- 1 | #sidebar= render 'shared/node_manager_sidebar' 2 | #main 3 | = form_for @node_group, :html => {:id => "param_form"} do |f| 4 | %input{:id => "force_create", :name => "force_create", :type => "hidden", :value => "false"} 5 | = render f 6 | .element.actions 7 | %button{:id => "submit_button"} Create 8 | or 9 | = link_to 'Cancel', node_groups_path 10 | %script{:type=>"text/javascript"} 11 | register_ajax_submit("#param_form"); 12 | -------------------------------------------------------------------------------- /app/views/nodes/_activity.html.haml: -------------------------------------------------------------------------------- 1 | .section.half 2 | %h3 Dashboard activity 3 | - unless node.timeline_events.empty? 4 | %ol.timeline= render node.timeline_events.recent(10) 5 | - else 6 | = describe_no_matches_for :activity 7 | 8 | %br.clear 9 | -------------------------------------------------------------------------------- /app/views/nodes/_description.html.haml: -------------------------------------------------------------------------------- 1 | - unless node.description.blank? 2 | .description= simple_format h(node.description) 3 | -------------------------------------------------------------------------------- /app/views/nodes/_facts.html.haml: -------------------------------------------------------------------------------- 1 | = inspector_table facts[:values].sort, :first, :last, :link => false, :key_title => :fact, :value_title => :value, :caption => "Current inventory for #{node.name} #{facts[:timestamp] ? "as of #{facts[:timestamp]}" : ""}" 2 | -------------------------------------------------------------------------------- /app/views/nodes/_hidden.html.haml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/app/views/nodes/_hidden.html.haml -------------------------------------------------------------------------------- /app/views/nodes/_inspections.html.haml: -------------------------------------------------------------------------------- 1 | - if node.reports.inspections.count > 0 2 | .section 3 | %h3 4 | Recent inspections 5 | %span.count== (#{node.reports.inspections.count}) 6 | - reports_limit = 10 7 | %table.inspector 8 | %thead 9 | %tr 10 | %th.status{:scope => :col} 11 | %th{:scope => :col} Reported at 12 | %th{:scope => :col} Total 13 | %th{:scope => :col} Runtime 14 | %tbody 15 | - node.reports.inspections.limit(reports_limit).each do |report| 16 | %tr 17 | = report_status_td(report) 18 | %td= link_to h(report.time), report 19 | %td= report.total_resources 20 | %td= report.total_time 21 | - if node.reports.inspections.count > reports_limit 22 | %tfoot 23 | %tr 24 | %td{:colspan => 5} 25 | .actionbar 26 | = link_to "More »".html_safe, reports_node_path(node, :kind => "inspect"), :class => 'button' 27 | -------------------------------------------------------------------------------- /app/views/nodes/_inventory_service.html.haml: -------------------------------------------------------------------------------- 1 | - if SETTINGS.enable_inventory_service 2 | .section 3 | %h3 Inventory 4 | %div#inventory 5 | = image_tag "/images/loading.gif" 6 | = "Loading node inventory" 7 | %script{:type => 'text/javascript'}!= load_asynchronously("div#inventory", facts_node_path(node)) 8 | 9 | %br.clear 10 | -------------------------------------------------------------------------------- /app/views/nodes/_log_detail.html.haml: -------------------------------------------------------------------------------- 1 | - nodes = paginate_scope(local_assigns[:nodes]) 2 | 3 | - unless nodes.empty? 4 | %table.inspector 5 | %thead 6 | %tr 7 | %th{:scope => :col} Hostname 8 | %th{:scope => :col} Level 9 | %th{:scope => :col} Message 10 | %th{:scope => :col} Source 11 | %th{:scope => :col} File 12 | %th{:scope => :col} Line 13 | %th{:scope => :col} Time 14 | %tbody 15 | - nodes.each do |node| 16 | - if node.last_apply_report.logs.present? 17 | - node.last_apply_report.logs.each do |log| 18 | - if (log.level == 'err') 19 | %tr.puppet_log 20 | %td.node 21 | = link_to h(node.name), node 22 | %td.loglevel 23 | = log.level 24 | %td 25 | = log.message 26 | %td 27 | = log.source 28 | %td 29 | = log.file 30 | %td 31 | = log.line 32 | %td.nowrap 33 | = link_to h(node.last_apply_report.time), node.last_apply_report 34 | - else 35 | %p 36 | = describe_no_matches_for :nodes 37 | -------------------------------------------------------------------------------- /app/views/nodes/_reports.html.haml: -------------------------------------------------------------------------------- 1 | - reports = node.reports.applies.limit(30).order('time ASC') 2 | - unless reports.empty? 3 | .section 4 | = render 'statuses/run_failure', :node => node 5 | 6 | .section 7 | = render 'statuses/run_time', :reports => reports.reverse 8 | 9 | .section 10 | %h3 11 | Recent reports 12 | %span.count== (#{node.reports.applies.count}) 13 | - reports_limit = 10 14 | = render 'reports/reports_table', 15 | :reports => paginate_scope(node.reports.applies, :per_page => reports_limit), 16 | :node => node, 17 | :tfoot => reports.count > reports_limit ? 'nodes/reports_table_tfoot' : nil 18 | -------------------------------------------------------------------------------- /app/views/nodes/_reports_table_tfoot.html.haml: -------------------------------------------------------------------------------- 1 | %tr 2 | %td{:colspan => 12} 3 | .actionbar 4 | = link_to "More »".html_safe, reports_node_path(node), :class => 'button' 5 | -------------------------------------------------------------------------------- /app/views/nodes/_search.html.haml: -------------------------------------------------------------------------------- 1 | = form_tag url_for(:action => action_name), :class => 'search', :method => :get do 2 | = text_field_tag 'q', params[:q] 3 | = hidden_field_tag('current', params[:current]) if params[:current].present? 4 | = hidden_field_tag('successful', params[:successful]) if params[:successful].present? 5 | %button Search 6 | -------------------------------------------------------------------------------- /app/views/nodes/edit.html.haml: -------------------------------------------------------------------------------- 1 | #sidebar= render 'shared/node_manager_sidebar' 2 | #main 3 | = form_for @node, :url => node_path(@node.id), :html => {:id => "param_form"} do |f| 4 | %input{:id => "force_update", :name => "force_update", :type => "hidden", :value => "false"} 5 | = render f 6 | .element.actions 7 | %button{:id => "submit_button"} Update 8 | or 9 | = link_to 'Cancel', node_path(@node.id) 10 | %script{:type=>"text/javascript"} 11 | register_ajax_submit("#param_form"); 12 | -------------------------------------------------------------------------------- /app/views/nodes/index.html.haml: -------------------------------------------------------------------------------- 1 | #sidebar= render 'shared/node_manager_sidebar' 2 | #main 3 | 4 | .header 5 | %h2.half 6 | - if action_name != 'index' 7 | = h action_name.titleize.capitalize 8 | nodes 9 | - else 10 | Nodes 11 | = describe_search_if_present 12 | = render 'search' 13 | %br.clear 14 | 15 | .item 16 | .section 17 | = render 'statuses/run_failure', :nodes => @nodes 18 | .section 19 | %h3 Nodes 20 | = render 'nodes', :nodes => @nodes, :selected_status => action_name 21 | %br.clear 22 | - if action_name == 'failed' 23 | .section 24 | %h3 Latest report errors 25 | = render 'log_detail', :nodes => @nodes 26 | %br.clear 27 | -------------------------------------------------------------------------------- /app/views/nodes/inventory_search.html.haml: -------------------------------------------------------------------------------- 1 | #sidebar= render :partial => 'shared/node_manager_sidebar' 2 | #main 3 | 4 | .header 5 | %h2.half Search nodes 6 | %br.clear 7 | 8 | .item 9 | .section 10 | = form_for url_for(:action => :search), :method => :get, :id => "search_params" do |form| 11 | = render :partial => 'parameters/parameter_input', :object => @search_params, :locals => { :entity_name => 'search criteria', :comparators => @comparators, :form_prefix => 'search_params' } 12 | %button#search_button Search 13 | 14 | - if @nodes 15 | .section 16 | = render :partial => 'statuses/run_failure', :locals => { :nodes => @nodes } 17 | .section 18 | %h3 Nodes 19 | = render :partial => 'nodes/nodes', :locals => { :nodes => @nodes } 20 | -------------------------------------------------------------------------------- /app/views/nodes/new.html.haml: -------------------------------------------------------------------------------- 1 | #sidebar= render 'shared/node_manager_sidebar' 2 | #main 3 | = form_for @node, :html => {:id => "param_form"} do |f| 4 | %input{:id => "force_create", :name => "force_create", :type => "hidden", :value => "false"} 5 | = render f 6 | .element.actions 7 | %button{:id => "submit_button"} Create 8 | or 9 | = link_to 'Cancel', @node 10 | %script{:type=>"text/javascript"} 11 | register_ajax_submit("#param_form"); 12 | -------------------------------------------------------------------------------- /app/views/nodes/show.html.haml: -------------------------------------------------------------------------------- 1 | #sidebar= render 'shared/node_manager_sidebar' 2 | #main 3 | .header 4 | %h2 5 | = node_status_icon(@node) 6 | Node: 7 | = h @node.name 8 | %span.alt= "(hidden)" if @node.hidden 9 | - unless SETTINGS.enable_read_only_mode || session['ACCESS_CONTROL_ROLE'] == 'READ_ONLY' 10 | %ul.actions 11 | %li= link_to 'Edit', edit_node_path(@node), :class => "edit button", :rel => 'inspect' 12 | - if @node.hidden 13 | %li= link_to 'Unhide', unhide_node_path(@node), :class => "hide button", :method => :put 14 | - else 15 | %li= link_to 'Hide', hide_node_path(@node), :class => "hide button", :method => :put 16 | %li= link_to 'Delete', @node, :data => {:confirm => 'Are you sure you wish to delete this node?'}, :method => :delete, :class => "delete button" 17 | .item 18 | .section#error_messages{:style => "display: none;"} 19 | 20 | - Registry.each_callback :core, :node_view_widgets do |widget| 21 | = widget.call self, @node 22 | -------------------------------------------------------------------------------- /app/views/pages/_node_summary_row.haml: -------------------------------------------------------------------------------- 1 | - nodes = local_assigns[:nodes] 2 | - title = local_assigns[:title] 3 | - class_name = local_assigns[:class_name] || title[/\w*/].downcase 4 | 5 | %tr{:class => class_name} 6 | %td.count 7 | %span= nodes.length 8 | %td 9 | %span.label= h title 10 | %em= "#{percentage(nodes)}%" 11 | %br/ 12 | %hr{:style => "width: #{percentage(nodes)}%"} 13 | -------------------------------------------------------------------------------- /app/views/pages/home.html.haml: -------------------------------------------------------------------------------- 1 | - tab_statuses = Node.home_statuses 2 | #sidebar= render 'shared/node_manager_sidebar' 3 | #main 4 | .item 5 | - if @all_nodes.empty? 6 | .section 7 | %p There are no nodes known by Dashboard. 8 | .section 9 | = render 'statuses/run_failure', :nodes => @all_nodes 10 | .item 11 | %ul#home-tabs.tabbed 12 | - tab_statuses.each do |tab_status| 13 | %li(id="#{tab_status}-tab") 14 | %a{:href => "##{tab_status}-tab"}= h tab_status.humanize 15 | - tab_statuses.each do |tab_status| 16 | %div.panel(id = tab_status) 17 | = render 'nodes/nodes', 18 | :nodes => instance_variable_get("@#{tab_status}_nodes"), 19 | :selected_status => tab_status, 20 | :more_link => url_for(:controller => "nodes", :action => tab_status == "all" ? :index : tab_status, :page => 2) 21 | %br.clear 22 | -------------------------------------------------------------------------------- /app/views/pages/index.html.haml: -------------------------------------------------------------------------------- 1 | #h2 Puppet Dashboard 2 | -------------------------------------------------------------------------------- /app/views/parameters/_parameter.html.haml: -------------------------------------------------------------------------------- 1 | %tr 2 | %td.key 3 | = parameter.key 4 | %td.value 5 | = parameter.value 6 | 7 | -------------------------------------------------------------------------------- /app/views/puppet/transaction/reports/_report.haml: -------------------------------------------------------------------------------- 1 | -# FIXME Is anything using this partial? 2 | .report.grouping 3 | %h2= h report.time 4 | 5 | .section 6 | %h3 Metrics 7 | - report.metrics.each do |name, metric| 8 | %table.inspector 9 | %caption= h name.capitalize 10 | = render metric 11 | 12 | .section 13 | %h3 Log 14 | %table.inspector 15 | %thead 16 | %tr 17 | %th{:scope => :col} Level 18 | %th{:scope => :col} Message 19 | %th{:scope => :col} Source 20 | %th{:scope => :col} Time 21 | %tbody 22 | = render report.logs 23 | 24 | .section 25 | %pre= h report.pretty_inspect 26 | -------------------------------------------------------------------------------- /app/views/puppet/util/logs/_log.haml: -------------------------------------------------------------------------------- 1 | %tr{:class => "puppet_log puppet_log_level_#{log.level}"} 2 | %td.level 3 | %code= h log.level 4 | %td 5 | %pre 6 | %code= h log.message 7 | %td.wrap= h wrap_on_slashes(log.source) 8 | %td.wrap= h wrap_on_slashes(log.file) 9 | %td.wrap= h log.line 10 | %td.wrap= h log.time 11 | -------------------------------------------------------------------------------- /app/views/reports/_log.html.haml: -------------------------------------------------------------------------------- 1 | .section 2 | %h3 Log 3 | - if report.logs.present? 4 | .section 5 | %table.inspector.puppet_log 6 | %thead 7 | %tr 8 | %th.log_level{:scope => :col} Level 9 | %th.message{:scope => :col} Message 10 | %th.source{:scope => :col} Source 11 | %th.file{:scope => :col} File 12 | %th.line{:scope => :col} Line 13 | %th.time{:scope => :col} Time 14 | %tbody 15 | = render :partial => 'puppet/util/logs/log', :collection => puppet_log_sorter(report.logs.compact) 16 | - else 17 | %p= describe_no_matches_for(:logs, :report) 18 | -------------------------------------------------------------------------------- /app/views/reports/_metrics.html.haml: -------------------------------------------------------------------------------- 1 | .section 2 | %h3 Metrics 3 | - if report.metrics.present? 4 | - report.metrics.group_by(&:category).sort.each do |category, metrics_in_category| 5 | .section 6 | %h4= h category.titleize 7 | %table.inspector 8 | = render :partial => 'metrics/metrics_table', :locals => {:metrics => metrics_in_category} 9 | - else 10 | %p= describe_no_matches_for(:metrics, :report) 11 | -------------------------------------------------------------------------------- /app/views/reports/_report.html.haml: -------------------------------------------------------------------------------- 1 | .header 2 | %h2 3 | = render :partial => 'report_title', :locals => { :report => report } 4 | - unless SETTINGS.enable_read_only_mode || session['ACCESS_CONTROL_ROLE'] == 'READ_ONLY' 5 | %ul.actions 6 | - Registry.each_callback :report, :actions do |thing| 7 | = thing.call self, report 8 | %li= link_to 'Delete', report, :data => {:confirm => 'Are you sure?'}, :method => :delete, :class => "delete button" 9 | 10 | .item 11 | - user_facing = Hash.new { |hash, key| hash[key] = key[/[a-z].*/i].titleize } 12 | - user_facing.update '800_resource_statuses' => 'Events' 13 | - panels = [] 14 | %ul#report-tabs.tabbed 15 | - Registry.each_callback :core, :report_view_widgets do |name, widget| 16 | - panel_id = user_facing[name].downcase 17 | - panels << capture_haml do 18 | %div.panel(id="#{panel_id}") 19 | = widget.call self, report 20 | %li(id="#{panel_id}-tab") 21 | %a(href= "##{panel_id}-tab")= h user_facing[name] 22 | - panels.each do |panel| 23 | = raw panel 24 | 25 | - Registry.each_callback :report, :tail do |thing| 26 | = thing.call self, report 27 | -------------------------------------------------------------------------------- /app/views/reports/_report_status_icon.html.haml: -------------------------------------------------------------------------------- 1 | - if report 2 | = icon(Registry.find_first_callback(:report, :status_icon) { |thing| thing.call(report) } || report.status, {:title => report ? report_title_text(report) : 'No reports'}) 3 | - else 4 | = icon(:error) 5 | -------------------------------------------------------------------------------- /app/views/reports/_report_status_td.html.haml: -------------------------------------------------------------------------------- 1 | %td.status{:class => report.status} 2 | = render :partial => 'reports/report_status_icon', :locals => { :report => report } 3 | -------------------------------------------------------------------------------- /app/views/reports/_report_title.html.haml: -------------------------------------------------------------------------------- 1 | %span.status{:class => report.status} 2 | = report_status_icon(report) 3 | Report: 4 | = link_to h(report.time), report 5 | %span.alt for 6 | = link_to h(report.node.name), report.node 7 | -------------------------------------------------------------------------------- /app/views/reports/index.html.haml: -------------------------------------------------------------------------------- 1 | - tab_statuses = Node.possible_statuses.unshift("all") 2 | #sidebar= render :partial => 'shared/node_manager_sidebar' 3 | #main 4 | .header 5 | %h2 6 | Reports 7 | - if @node 8 | %span.alt for 9 | = link_to h(@node.name), @node 10 | %span.count== (#{@reports.total_entries}) 11 | 12 | .item 13 | - if @tab 14 | %ul#report-tabs.tabbed 15 | - tab_statuses.each do |tab_status| 16 | %li{:id => "#{tab_status}-tab", :class => (tab_status == @tab ? 'active' : '') } 17 | - if tab_status == 'all' 18 | %a{:href => url_for(:status => nil)}= h tab_status.humanize 19 | - else 20 | %a{:href => url_for(:status => tab_status)}= h tab_status.humanize 21 | = render :partial => 'reports/reports_table', :locals => { :reports => @reports, :node => @node } 22 | 23 | %br.clear 24 | -------------------------------------------------------------------------------- /app/views/reports/show.html.haml: -------------------------------------------------------------------------------- 1 | #sidebar= render :partial => 'shared/node_manager_sidebar' 2 | #main 3 | %div{ :class => @report ? @report.kind + '-report' : '' } 4 | = render :partial => 'report', :locals => { :report => @report } 5 | -------------------------------------------------------------------------------- /app/views/shared/_class_parameter_conflicts_table.html.haml: -------------------------------------------------------------------------------- 1 | %table.inspector{:style => 'margin-top: 1.5em;'} 2 | %thead 3 | %tr 4 | %th{:scope => :col} Class 5 | %th{:scope => :col} Parameter 6 | %th{:scope => :col} Value 7 | %th{:scope => :col} Source 8 | %tbody 9 | - conflicts.keys.sort_by { |node_class| node_class.name }.each do |node_class| 10 | %tr 11 | - class_srcs_cnt = 0 12 | - conflicts[node_class].each { |param| param[:sources].each { |item| class_srcs_cnt += 1 }} 13 | %td{:rowspan => class_srcs_cnt} 14 | %strong= h(node_class.name) 15 | - first_param = true 16 | - conflicts[node_class].sort_by{ |param| param[:name] }.each do |param| 17 | - if first_param 18 | - first_param = false 19 | = render 'shared/parameters_part1', :param => param, :node_class_id => node_class.id, :links => false 20 | - else 21 | %tr 22 | = render 'shared/parameters_part1', :param => param, :node_class_id => node_class.id, :links => false 23 | -------------------------------------------------------------------------------- /app/views/shared/_confirm.html.haml: -------------------------------------------------------------------------------- 1 | #popupWindowGlass 2 | #popupWindowLayoutHelperTable 3 | #popupWindowLayoutHelperTableCell 4 | #popupWindow 5 | = raw message 6 | #popupWindowButtons 7 | %button{:onclick => on_confirm_clicked_script} 8 | = confirm_label 9 | or 10 | = link_to 'Cancel', '#', :onclick => "jQuery('#popupWindowGlass').parent().detach(); return false;" 11 | -------------------------------------------------------------------------------- /app/views/shared/_error.html.haml: -------------------------------------------------------------------------------- 1 | = error_messages_for(object_name, :object => object) -------------------------------------------------------------------------------- /app/views/shared/_form_errors.html.haml: -------------------------------------------------------------------------------- 1 | - unless form_errors.empty? 2 | %div{:id => "error_explanation"} 3 | %h2= pluralize(form_errors.count, "error") + ":" 4 | %ul 5 | - form_errors.full_messages.each do |msg| 6 | %li= msg 7 | -------------------------------------------------------------------------------- /app/views/shared/_groups.html.haml: -------------------------------------------------------------------------------- 1 | .section.half 2 | %h3 Groups 3 | - unless resource.all_node_groups.empty? 4 | %table.inspector 5 | %thead 6 | %tr 7 | %th{:scope => :col} Group 8 | %th{:scope => :col} Source 9 | %tbody 10 | - resource.node_groups_with_sources.sort.each do |group,sources| 11 | %tr 12 | %td 13 | %strong= link_to(h(group.name),group) 14 | %td 15 | - if sources.include?(resource) 16 | = h resource.name 17 | - else 18 | = raw sources.map{ |source| link_to(h(source.name), source) }.join(", ") 19 | - else 20 | = describe_no_matches_as 'No groups' 21 | -------------------------------------------------------------------------------- /app/views/shared/_inspector.html.haml: -------------------------------------------------------------------------------- 1 | %table.inspector 2 | - if options[:caption] 3 | %caption= h options[:caption] 4 | %thead 5 | %tr 6 | %th.key= h(options[:key_title] || key).to_s.titleize 7 | - unless options[:key_only] 8 | %th.value{:colspan => 2}= h(options[:value_title] || value).to_s.titleize 9 | %tbody 10 | - inspector.each do |key, value| 11 | %tr 12 | %td.key= h key 13 | - unless options[:key_only] 14 | %td{:colspan => 2}= h value 15 | -------------------------------------------------------------------------------- /app/views/shared/_node_manager_sidebar_for_type.html.haml: -------------------------------------------------------------------------------- 1 | -# Render a sidebar section for a +type+ (e.g. NodeGroup or NodeClass). 2 | 3 | - add_body_class 'with-sidebar' 4 | - table = type.name.tableize 5 | - label = type.name.sub(/Node/, '') 6 | - ivar = instance_variable_get "@#{table.singularize}" 7 | - path_for_index = "#{table}_path" 8 | - path_for_new = "new_#{table.singularize}_path" 9 | - path_for_show = "#{table.singularize}_path" 10 | 11 | .group 12 | %h3{:class => active_if(controller_name == table && action_name == "index")}= link_to(h(label.pluralize), send(path_for_index)) 13 | - entries = type.with_nodes_count 14 | - unless entries.empty? 15 | %ul 16 | - for entry in entries 17 | %li{:class => active_if(controller_name == table && ivar && ivar == entry)} 18 | = link_to h(entry.name), send(path_for_show, entry) 19 | %span.count= entry.nodes_count 20 | .footer.actionbar 21 | - unless SETTINGS.enable_read_only_mode || session['ACCESS_CONTROL_ROLE'] == 'READ_ONLY' 22 | = link_to "Add #{h(label.downcase)}", send(path_for_new), :class => 'button' 23 | -------------------------------------------------------------------------------- /app/views/shared/_node_summary.html.haml: -------------------------------------------------------------------------------- 1 | %table.node_summary 2 | %tr{:style => 'text-color: white;'} 3 | %td{:colspan => 2} 4 | Puppet Node Summary 5 | %span#status 6 | 7 | - @node_summary['display'].each do |status_pair| 8 | - status = status_pair['key'] 9 | - node_count = @node_summary[status] 10 | - all_node_count = @node_summary['all'] 11 | - if (status == 'all') 12 | - percent = '0' 13 | - else 14 | - percent = percentage(node_count, all_node_count) 15 | 16 | %tr{:class => status} 17 | %td.count_column 18 | %p.count 19 | %span 20 | = node_count 21 | %td 22 | %div 23 | %p.label 24 | %span 25 | = status_pair['name'] 26 | %p.percent{:style => "width: #{percent}%"} 27 | %span 28 | = status_pair['name'] 29 | -------------------------------------------------------------------------------- /app/views/shared/_parameters.html.haml: -------------------------------------------------------------------------------- 1 | .section 2 | %h3 Parameters 3 | - # Conflicting parameters are okay here, since we just want to warn 4 | - unless parent.compile_class_parameters(membership, true).empty? 5 | - if parent.errors.has_key?(:classParameters) 6 | %p.error 7 | %strong Warning: 8 | Parameter values conflict. 9 | %table.inspector 10 | %thead 11 | %tr 12 | %th{:scope => :col} Key 13 | %th{:scope => :col} Value 14 | %th{:scope => :col} Source 15 | %tbody 16 | - parent.compile_class_parameters(membership, true).sort_by{ |param| param[:name] }.each do |param| 17 | %tr 18 | = render 'shared/parameters_part1', :param => param, :node_class_id => node_class.id 19 | - else 20 | = describe_no_matches_as 'No parameters' 21 | -------------------------------------------------------------------------------- /app/views/shared/_parameters_part1.html.haml: -------------------------------------------------------------------------------- 1 | - use_links = !defined?(links) || links 2 | %td{:rowspan => param[:sources].length} 3 | %tt= h param[:name] 4 | - first_src = true 5 | - param[:sources].sort_by{ |source| source.name }.each do |source| 6 | - if first_src 7 | - first_src = false 8 | = render 'shared/parameters_part2', :source => source, :param => param, :node_class_id => node_class_id, :links => use_links 9 | - else 10 | %tr 11 | = render 'shared/parameters_part2', :source => source, :param => param, :node_class_id => node_class_id, :links => use_links -------------------------------------------------------------------------------- /app/views/shared/_parameters_part2.html.haml: -------------------------------------------------------------------------------- 1 | %td{:style => ("background-color: pink;" if param[:sources].size > 1)} 2 | %tt= ConflictAnalyzer.get_parameter_value(source, param[:name], node_class_id) 3 | %td 4 | %tt= links ? link_to(h(source.name),node_group_path(source.id)) : h(source.name) 5 | -------------------------------------------------------------------------------- /app/views/shared/_search.html.haml: -------------------------------------------------------------------------------- 1 | = form_tag request.url, :class => 'search', :method => :get do 2 | = text_field_tag 'q', params[:q] 3 | %button Search 4 | -------------------------------------------------------------------------------- /app/views/shared/_skiplink.html.haml: -------------------------------------------------------------------------------- 1 | %a#skiplink{:href => "#skiptarget"} 2 | = "Skip to main content (Press Enter)." 3 | -------------------------------------------------------------------------------- /app/views/shared/_skiptarget.html.haml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/views/shared/_tokenized_text_box.html.haml: -------------------------------------------------------------------------------- 1 | .element{:class => "#{model.pluralize}"} 2 | = label_tag title 3 | = text_field_tag "#{source}[assigned_#{model}_ids][]", '', :id => "#{model}_ids" 4 | -------------------------------------------------------------------------------- /app/views/shared/_variable_conflicts_table.html.haml: -------------------------------------------------------------------------------- 1 | %table.inspector{:style => 'margin-top: 1.5em;'} 2 | %thead 3 | %tr 4 | %th{:scope => :col} Variable 5 | %th{:scope => :col} Value 6 | %th{:scope => :col} Source 7 | %tbody 8 | - conflicts.sort_by { |conflict| conflict[:name] }.each do |conflict| 9 | %tr 10 | = render 'shared/parameters_part1', :param => conflict, :node_class_id => nil, :links => false -------------------------------------------------------------------------------- /app/views/shared/_variables.html.haml: -------------------------------------------------------------------------------- 1 | .section 2 | %h3 Variables 3 | - # Conflicting variables are okay here, since we just want to warn 4 | - unless resource.compiled_parameters(true).empty? 5 | - if resource.errors.has_key?(:parameters) 6 | %p.error 7 | %strong Warning: 8 | Variable values conflict. 9 | %table.inspector 10 | %thead 11 | %tr 12 | %th{:scope => :col} Key 13 | %th{:scope => :col} Value 14 | %th{:scope => :col} Source 15 | %tbody 16 | - resource.compiled_parameters(true).sort_by{ |param| param[:name] }.each do |param| 17 | %tr 18 | = render 'shared/parameters_part1', :param => param, :node_class_id => nil 19 | - else 20 | = describe_no_matches_as 'No variables' 21 | -------------------------------------------------------------------------------- /app/views/statuses/_run_failure.html.haml: -------------------------------------------------------------------------------- 1 | - nodes = local_assigns[:nodes] 2 | - node = local_assigns[:node] 3 | - args = {} 4 | - args[:node] = node if node 5 | - args[:nodes] = nodes if nodes 6 | - statuses = Status.within_daily_run_history(args) 7 | 8 | %h3 Daily run status 9 | %p.legend Number and status of runs during the last #{SETTINGS.daily_run_history_length} days: 10 | 11 | - if statuses.present? 12 | %table.inspector.data.status.bar 13 | %thead 14 | %tr.labels 15 | - statuses.each do |status| 16 | %th{:scope => :col}= status.start.strftime('%b-%d') 17 | %tbody 18 | %tr.unchanged 19 | - statuses.each do |status| 20 | %td= status.unchanged 21 | %tr.changed 22 | - statuses.each do |status| 23 | %td= status.changed 24 | %tr.pending 25 | - statuses.each do |status| 26 | %td= status.pending 27 | %tr.failed 28 | - statuses.each do |status| 29 | %td= status.failed 30 | - else 31 | %p 32 | = describe_no_matches_as 'No runs found to report' 33 | -------------------------------------------------------------------------------- /app/views/statuses/_run_time.html.haml: -------------------------------------------------------------------------------- 1 | - if reports.size > 1 2 | %h3 Run Time 3 | %p.legend The elapsed time in seconds for each of the last 30 Puppet runs: 4 | %table.inspector.data.runtime 5 | %thead 6 | %tr.labels 7 | - reports.map{|r| r.time}.each do |time| 8 | %th{:scope => :col}= time.to_s(:time) 9 | %tbody 10 | %tr.runtimes 11 | - reports.map{|r| r.total_time}.compact.each do |time| 12 | %td= "%0.2f" % time.to_f 13 | %br.clear 14 | -------------------------------------------------------------------------------- /app/views/statuses/show.html.haml: -------------------------------------------------------------------------------- 1 | .item 2 | .section 3 | = render :partial => 'statuses/run_failure' 4 | .section 5 | - reports = Report.all(:limit => 30, :order => 'time DESC') 6 | = render :partial => 'statuses/run_time', :locals => { :reports => reports } 7 | -------------------------------------------------------------------------------- /app/views/timeline_events/_timeline_event.html.haml: -------------------------------------------------------------------------------- 1 | - te = timeline_event 2 | - if te and te.subject 3 | - if @node 4 | - is_current = te.subject == @node 5 | - subject_name = te.subject_name 6 | - subject = is_current ? "This node" : subject_name 7 | 8 | - is_secondary = te.secondary_subject == @node 9 | - secondary_name = te.secondary_subject && te.secondary_name 10 | - secondary = is_secondary ? "this node" : secondary_name 11 | 12 | %li{:class => te.object_type} 13 | %span.date 14 | = h te.created_at 15 | → 16 | -# Not all subjects can be linked, e.g. you can't link to a Parameter 17 | - if not is_current and link = link_to(h(subject), te.subject) rescue nil 18 | = h te.subject_type 19 | = link 20 | - else 21 | = h subject 22 | = h te.action 23 | = link_to_unless is_secondary, h(secondary), te.secondary_subject if te.secondary_subject_type 24 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /bin/delayed_job: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment')) 4 | require 'delayed/command' 5 | Delayed::Command.new(ARGV).daemonize 6 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../config/application', __dir__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'fileutils' 3 | include FileUtils 4 | 5 | # path to your application root. 6 | APP_ROOT = File.expand_path('..', __dir__) 7 | 8 | def system!(*args) 9 | system(*args) || abort("\n== Command #{args} failed ==") 10 | end 11 | 12 | chdir APP_ROOT do 13 | # This script is a starting point to setup your application. 14 | # Add necessary setup steps to this file. 15 | 16 | puts '== Installing dependencies ==' 17 | system! 'gem install bundler --conservative' 18 | system('bundle check') || system!('bundle install') 19 | 20 | # Install JavaScript dependencies if using Yarn 21 | # system('bin/yarn') 22 | 23 | # puts "\n== Copying sample files ==" 24 | # unless File.exist?('config/database.yml') 25 | # cp 'config/database.yml.sample', 'config/database.yml' 26 | # end 27 | 28 | puts "\n== Preparing database ==" 29 | system! 'bin/rails db:setup' 30 | 31 | puts "\n== Removing old logs and tempfiles ==" 32 | system! 'bin/rails log:clear tmp:clear' 33 | 34 | puts "\n== Restarting application server ==" 35 | system! 'bin/rails restart' 36 | end 37 | -------------------------------------------------------------------------------- /bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'fileutils' 3 | include FileUtils 4 | 5 | # path to your application root. 6 | APP_ROOT = File.expand_path('..', __dir__) 7 | 8 | def system!(*args) 9 | system(*args) || abort("\n== Command #{args} failed ==") 10 | end 11 | 12 | chdir APP_ROOT do 13 | # This script is a way to update your development environment automatically. 14 | # Add necessary update steps to this file. 15 | 16 | puts '== Installing dependencies ==' 17 | system! 'gem install bundler --conservative' 18 | system('bundle check') || system!('bundle install') 19 | 20 | # Install JavaScript dependencies if using Yarn 21 | # system('bin/yarn') 22 | 23 | puts "\n== Updating database ==" 24 | system! 'bin/rails db:migrate' 25 | 26 | puts "\n== Removing old logs and tempfiles ==" 27 | system! 'bin/rails log:clear tmp:clear' 28 | 29 | puts "\n== Restarting application server ==" 30 | system! 'bin/rails restart' 31 | end 32 | -------------------------------------------------------------------------------- /bin/yarn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_ROOT = File.expand_path('..', __dir__) 3 | Dir.chdir(APP_ROOT) do 4 | begin 5 | exec "yarnpkg", *ARGV 6 | rescue Errno::ENOENT 7 | $stderr.puts "Yarn executable was not detected in the system." 8 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" 9 | exit 1 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative 'config/environment' 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | 3 | require 'rails/all' 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module PuppetDashboard 10 | class Application < Rails::Application 11 | # Settings in config/environments/* take precedence over those specified here. 12 | # Application configuration can go into files in config/initializers 13 | # -- all .rb files in that directory are automatically loaded after loading 14 | # the framework and any gems in your application. 15 | 16 | # TODO: We will have to move to move this to app/lib eventually 17 | Rails.application.config.eager_load_paths << Rails.root.join('lib') 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | require 'bootsnap/setup' # Speed up boot time by caching expensive operations. 5 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: async 6 | 7 | production: 8 | adapter: redis 9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 10 | channel_prefix: puppet_dashboard_production 11 | -------------------------------------------------------------------------------- /config/database.yml.travis: -------------------------------------------------------------------------------- 1 | # Each of the sections matches a DB env in .travis.yml 2 | 3 | mysql: &mysql 4 | adapter: mysql2 5 | username: root 6 | database: dashboard_test 7 | encoding: utf8 8 | 9 | postgres: &postgres 10 | adapter: postgresql 11 | username: postgres 12 | database: dashboard_test 13 | encoding: utf8 14 | 15 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/initializers/00_settings_reader_init.rb: -------------------------------------------------------------------------------- 1 | # Read settings 2 | require 'settings_reader' 3 | SETTINGS = SettingsReader.read 4 | -------------------------------------------------------------------------------- /config/initializers/ZZZ_load_plugin_initializers.rb: -------------------------------------------------------------------------------- 1 | Dir[Rails.root.join('config', 'installed_plugins', '*')].sort.each do |plugin| 2 | plugin = File.basename(plugin) 3 | dir = Rails.root.join('vendor', 'plugins', plugin) 4 | 5 | Dir[dir.join('config', 'initializers', '**', '*.rb')].sort.each do |file| 6 | load(file) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /config/initializers/app_version_init.rb: -------------------------------------------------------------------------------- 1 | # Get the Dashboard version number. 2 | # 3 | # Any officially released package or tarball of dashboard 4 | # will have a VERSION file that is generated at tarball 5 | # build time. 6 | # 7 | # This allows for the APP_VERSION to be determined by git, so 8 | # developers can run out of master after a git checkout. 9 | def get_app_version 10 | if File.exists?(Rails.root.join('VERSION')) 11 | return File.read(Rails.root.join('VERSION')).strip 12 | elsif File.directory?(Rails.root.join('.git')) 13 | return `cd '#{Rails.root}'; git describe`.strip! rescue 'unknown' 14 | end 15 | 16 | 'unknown' 17 | end 18 | 19 | def get_app_version_link 20 | if File.exists?(Rails.root.join('VERSION_LINK')) 21 | return File.read(Rails.root.join('VERSION_LINK')).strip 22 | else 23 | return "https://github.com/sodabrew/puppet-dashboard/commits/#{APP_VERSION.sub(/.*?g([0-9a-f]*)/, "\\1")}" 24 | end 25 | end 26 | 27 | APP_VERSION = get_app_version 28 | APP_VERSION_LINK = get_app_version_link 29 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ActiveSupport::Reloader.to_prepare do 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | # end 9 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | # Add Yarn node_modules folder to the asset load path. 9 | Rails.application.config.assets.paths << Rails.root.join('node_modules') 10 | 11 | # Precompile additional assets. 12 | # application.js, application.css, and all non-JS/CSS in the app/assets 13 | # folder are already added. 14 | Rails.application.config.assets.precompile += %w( application.radiator.js application.radiator.css ) 15 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/check_migration_version.rb: -------------------------------------------------------------------------------- 1 | # Lifted from Advanced Rails Recipes #38: Fail Early -- 2 | # Check to make sure we've got the right database version; 3 | # skip when run from tasks like rake db:migrate, or from Capistrano rules 4 | # that need to run before the migration rule 5 | current_version = ActiveRecord::Migrator.current_version rescue 0 6 | highest_version = Dir.glob("#{Rails.root}/db/migrate/*.rb" ).map { |f| 7 | f.match(/(\d+)_.*\.rb$/) ? $1.to_i : 0 8 | }.max 9 | 10 | abort "Database isn't the current migration version: " \ 11 | "expected #{highest_version}, got #{current_version}\n" \ 12 | "You must either run 'rake db:migrate' or set environmental variable NO_MIGRATION_CHECK" \ 13 | unless current_version == highest_version or \ 14 | defined?(Rake) or ENV['NO_MIGRATION_CHECK'] 15 | 16 | -------------------------------------------------------------------------------- /config/initializers/clear_cached_assets.rb: -------------------------------------------------------------------------------- 1 | [ 2 | "#{Rails.root}/public/javascripts/all.js", 3 | "#{Rails.root}/public/stylesheets/all.css", 4 | ].each do |filename| 5 | FileUtils.rm(filename) if File.exist?(filename) 6 | end 7 | -------------------------------------------------------------------------------- /config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy 4 | # For further information see the following documentation 5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy 6 | 7 | # Rails.application.config.content_security_policy do |policy| 8 | # policy.default_src :self, :https 9 | # policy.font_src :self, :https, :data 10 | # policy.img_src :self, :https, :data 11 | # policy.object_src :none 12 | # policy.script_src :self, :https 13 | # policy.style_src :self, :https 14 | 15 | # # Specify URI for violation reports 16 | # # policy.report_uri "/csp-violation-report-endpoint" 17 | # end 18 | 19 | # If you are using UJS then enable automatic nonce generation 20 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } 21 | 22 | # Report CSP violations to a specified URI 23 | # For further information see the following documentation: 24 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only 25 | # Rails.application.config.content_security_policy_report_only = true 26 | -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /config/initializers/delayed_job.rb: -------------------------------------------------------------------------------- 1 | Delayed::Worker.destroy_failed_jobs = false 2 | Delayed::Worker.max_attempts = 3 3 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /config/initializers/requires.rb: -------------------------------------------------------------------------------- 1 | # Local libraries 2 | require "#{Rails.root}/lib/has_parameters" 3 | require "#{Rails.root}/lib/csv_extensions" 4 | require "#{Rails.root}/lib/add_renderers" 5 | require "#{Rails.root}/lib/registry" 6 | require "#{Rails.root}/lib/core_callbacks" 7 | require "#{Rails.root}/lib/puppet/report_sanitizer" 8 | -------------------------------------------------------------------------------- /config/initializers/safe_yaml.rb: -------------------------------------------------------------------------------- 1 | require 'safe_yaml' 2 | 3 | # Set default for YAML.load to unsafe so we don't affect performance 4 | # unnecessarily -- we call it safely explicitly where needed 5 | SafeYAML::OPTIONS[:default_mode] = :unsafe 6 | 7 | # Whitelist Symbol objects 8 | SafeYAML::OPTIONS[:whitelisted_tags] << 'tag:ruby.yaml.org,2002:sym' #syck 9 | SafeYAML::OPTIONS[:whitelisted_tags] << '!ruby/sym' #psych 10 | -------------------------------------------------------------------------------- /config/initializers/sass.rb: -------------------------------------------------------------------------------- 1 | # Sass fails to regenerate in production mode at an appropriate time, which 2 | # yields a server error (500), followed by some unstyled content. Unsetting 3 | # this constant in an initializer prompts Sass to ensure that the stylesheets 4 | # are generated at the appropriate time. This only applies to the initial 5 | # page load; subsequent requests are appropriately cached and will exhibit the 6 | # former behavior when provoked. 7 | if defined?(Sass::RAILS_LOADED) 8 | module Sass 9 | remove_const(:RAILS_LOADED) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_puppet_dashboard_session' 4 | -------------------------------------------------------------------------------- /config/initializers/time_formats.rb: -------------------------------------------------------------------------------- 1 | # TODO make format customizable through an external configuration file. 2 | Time::DATE_FORMATS.update( 3 | # :default => lambda{|time| time.strftime('%m/%d/%y ') + time.strftime('%I:%M%p').downcase } 4 | :default => lambda{|time| time.in_time_zone.strftime(SETTINGS.datetime_format) }, 5 | :date => lambda{|time| time.in_time_zone.strftime(SETTINGS.date_format) }, 6 | :time => lambda{|time| time.in_time_zone.strftime('%I:%M%p') } 7 | ) 8 | Date::DATE_FORMATS.update( 9 | :default => SETTINGS.date_format 10 | ) 11 | 12 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # 'true': 'foo' 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at http://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /config/preinitializer.rb: -------------------------------------------------------------------------------- 1 | require 'thread' 2 | -------------------------------------------------------------------------------- /config/spring.rb: -------------------------------------------------------------------------------- 1 | %w[ 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | ].each { |path| Spring.watch(path) } 7 | -------------------------------------------------------------------------------- /config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | 9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) 10 | # amazon: 11 | # service: S3 12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> 13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> 14 | # region: us-east-1 15 | # bucket: your_own_bucket 16 | 17 | # Remember not to checkin your GCS keyfile to a repository 18 | # google: 19 | # service: GCS 20 | # project: your_project 21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> 22 | # bucket: your_own_bucket 23 | 24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) 25 | # microsoft: 26 | # service: AzureStorage 27 | # storage_account_name: your_account_name 28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> 29 | # container: your_container_name 30 | 31 | # mirror: 32 | # service: Mirror 33 | # primary: local 34 | # mirrors: [ amazon, google, microsoft ] 35 | -------------------------------------------------------------------------------- /db/migrate/20090916215745_basic_schema.rb: -------------------------------------------------------------------------------- 1 | class BasicSchema < ActiveRecord::Migration[4.2] 2 | def self.up 3 | create_table :assignments, :force => true do |t| 4 | t.integer :node_id 5 | t.integer :service_id 6 | t.datetime :created_at 7 | t.datetime :updated_at 8 | end 9 | 10 | create_table :nodes, :force => true do |t| 11 | t.string :name 12 | t.text :description 13 | t.datetime :created_at 14 | t.datetime :updated_at 15 | t.text :parameters 16 | end 17 | 18 | create_table :services, :force => true do |t| 19 | t.string :name 20 | t.string :type 21 | t.text :description 22 | t.datetime :created_at 23 | t.datetime :updated_at 24 | end 25 | end 26 | 27 | def self.down 28 | drop_table :assignments 29 | drop_table :nodes 30 | drop_table :services 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /db/migrate/20090916221313_create_node_group_memberships.rb: -------------------------------------------------------------------------------- 1 | class CreateNodeGroupMemberships < ActiveRecord::Migration[4.2] 2 | def self.up 3 | create_table :node_group_memberships do |t| 4 | t.integer :node_id 5 | t.integer :node_group_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | 11 | def self.down 12 | drop_table :node_group_memberships 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20090917163433_create_node_classes.rb: -------------------------------------------------------------------------------- 1 | class CreateNodeClasses < ActiveRecord::Migration[4.2] 2 | def self.up 3 | create_table :node_classes do |t| 4 | t.string :name 5 | 6 | t.timestamps 7 | end 8 | end 9 | 10 | def self.down 11 | drop_table :node_classes 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20090917163500_create_node_class_memberships.rb: -------------------------------------------------------------------------------- 1 | class CreateNodeClassMemberships < ActiveRecord::Migration[4.2] 2 | def self.up 3 | create_table :node_class_memberships do |t| 4 | t.integer :node_id 5 | t.integer :node_class_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | 11 | def self.down 12 | drop_table :node_class_memberships 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20090921151631_create_node_groups.rb: -------------------------------------------------------------------------------- 1 | class CreateNodeGroups < ActiveRecord::Migration[4.2] 2 | def self.up 3 | create_table :node_groups do |t| 4 | t.string :name 5 | 6 | t.timestamps 7 | end 8 | end 9 | 10 | def self.down 11 | drop_table :node_groups 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20091025181245_create_node_group_class_memberships.rb: -------------------------------------------------------------------------------- 1 | class CreateNodeGroupClassMemberships < ActiveRecord::Migration[4.2] 2 | def self.up 3 | create_table :node_group_class_memberships do |t| 4 | t.belongs_to :node_group 5 | t.belongs_to :node_class 6 | 7 | t.timestamps 8 | end 9 | end 10 | 11 | def self.down 12 | drop_table :node_group_class_memberships 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20091025182048_add_parameters_to_node_groups.rb: -------------------------------------------------------------------------------- 1 | class AddParametersToNodeGroups < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :node_groups, :parameters, :text 4 | end 5 | 6 | def self.down 7 | remove_column :node_groups, :parameters 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20091028174517_create_timeline_events.rb: -------------------------------------------------------------------------------- 1 | class CreateTimelineEvents < ActiveRecord::Migration[4.2] 2 | def self.up 3 | create_table :timeline_events do |t| 4 | t.string :event_type, :subject_type, :actor_type, :secondary_subject_type 5 | t.integer :subject_id, :actor_id, :secondary_subject_id 6 | t.timestamps 7 | end 8 | end 9 | 10 | def self.down 11 | drop_table :timeline_events 12 | end 13 | end 14 | 15 | 16 | -------------------------------------------------------------------------------- /db/migrate/20091110002528_create_parameters.rb: -------------------------------------------------------------------------------- 1 | class CreateParameters < ActiveRecord::Migration[4.2] 2 | def self.up 3 | create_table :parameters do |t| 4 | t.string :key 5 | t.text :value 6 | t.integer :parameterable_id 7 | t.string :parameterable_type 8 | 9 | t.timestamps 10 | end 11 | end 12 | 13 | def self.down 14 | drop_table :parameters 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20091110005353_remove_parameters_from_node.rb: -------------------------------------------------------------------------------- 1 | class RemoveParametersFromNode < ActiveRecord::Migration[4.2] 2 | def self.up 3 | remove_column :nodes, :parameters 4 | end 5 | 6 | def self.down 7 | add_column :nodes, :parameters, :text 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20091116212418_create_node_group_edges.rb: -------------------------------------------------------------------------------- 1 | class CreateNodeGroupEdges < ActiveRecord::Migration[4.2] 2 | def self.up 3 | create_table :node_group_edges do |t| 4 | t.integer :to_id 5 | t.integer :from_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | 11 | def self.down 12 | drop_table :node_group_edges 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20091116235339_remove_parameters_from_node_groups.rb: -------------------------------------------------------------------------------- 1 | class RemoveParametersFromNodeGroups < ActiveRecord::Migration[4.2] 2 | def self.up 3 | remove_column :node_groups, :parameters 4 | end 5 | 6 | def self.down 7 | add_column :node_groups, :parameters, :text 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20091120013227_create_reports.rb: -------------------------------------------------------------------------------- 1 | class CreateReports < ActiveRecord::Migration[4.2] 2 | def self.up 3 | create_table :reports do |t| 4 | t.integer :node_id 5 | t.text :report 6 | 7 | t.timestamps 8 | end 9 | end 10 | 11 | def self.down 12 | drop_table :reports 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20091130201400_add_url_to_node.rb: -------------------------------------------------------------------------------- 1 | class AddUrlToNode < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :nodes, :url, :string 4 | end 5 | 6 | def self.down 7 | remove_column :nodes, :url 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20091208225308_add_reported_at_to_node.rb: -------------------------------------------------------------------------------- 1 | class AddReportedAtToNode < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :nodes, :reported_at, :timestamp 4 | 5 | begin 6 | STDOUT.puts "-- migrate Node data" 7 | ms = Benchmark.ms do 8 | nodes = Node.all.to_a.select{|n| n.last_report.respond_to?(:report)} 9 | if nodes.size > 0 10 | pbar = ProgressBar.create(title: ' ->', total: nodes.size) 11 | ms = Benchmark.ms do 12 | nodes.each{|n| n.update_attribute(:reported_at, n.last_report.report.time); pbar.increment} 13 | pbar.finish 14 | end 15 | end 16 | end 17 | rescue => e 18 | STDERR.puts " -> Error: " << e.message 19 | end 20 | end 21 | 22 | def self.down 23 | remove_column :nodes, :reported_at 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /db/migrate/20091215194836_add_success_to_report.rb: -------------------------------------------------------------------------------- 1 | class AddSuccessToReport < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :reports, :success, :boolean 4 | end 5 | 6 | def self.down 7 | remove_column :reports, :success 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20091217192540_add_host_and_time_to_report.rb: -------------------------------------------------------------------------------- 1 | class AddHostAndTimeToReport < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :reports, :host, :string 4 | add_column :reports, :time, :datetime 5 | end 6 | 7 | def self.down 8 | remove_column :reports, :time 9 | remove_column :reports, :host 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20091217212330_migrate_report_data.rb: -------------------------------------------------------------------------------- 1 | class MigrateReportData < ActiveRecord::Migration[4.2] 2 | def self.up 3 | STDOUT.puts "-- migrate Report data" 4 | reports = Report.all.to_a 5 | if reports.size > 0 6 | pbar = ProgressBar.create(title: ' ->', total: reports.size) 7 | ms = Benchmark.ms do 8 | reports.each{|r| r.send(:set_attributes); r.save_without_validation; pbar.increment} 9 | end 10 | end 11 | ensure 12 | pbar and pbar.finish 13 | end 14 | 15 | def self.down 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /db/migrate/20100318131825_add_indexes.rb: -------------------------------------------------------------------------------- 1 | class AddIndexes < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_index :reports, :time 4 | add_index :reports, :node_id 5 | end 6 | 7 | def self.down 8 | remove_index :reports, :node_id 9 | remove_index :reports, :time 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20100726070117_add_success_and_last_report_to_nodes.rb: -------------------------------------------------------------------------------- 1 | class AddSuccessAndLastReportToNodes < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :nodes, :success, :boolean, :default => false 4 | add_column :nodes, :last_report_id, :integer 5 | 6 | Node.reset_column_information 7 | 8 | nodes = Node.all.to_a 9 | if nodes.size > 0 10 | pbar = ProgressBar.create(title: 'Migrating', total: nodes.size) 11 | nodes.each do |node| 12 | report = node.find_last_report 13 | pbar.increment 14 | next unless report 15 | report.send(:update_node, true) 16 | end 17 | pbar.finish 18 | end 19 | end 20 | 21 | def self.down 22 | remove_column :nodes, :success 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /db/migrate/20100806181533_cleanup_node_memberships.rb: -------------------------------------------------------------------------------- 1 | class CleanupNodeMemberships < ActiveRecord::Migration[4.2] 2 | def self.up 3 | NodeClassMembership.all.each do |n| 4 | n.destroy if n.node_class.nil? || n.node.nil? 5 | end 6 | NodeGroupMembership.all.each do |n| 7 | n.destroy if n.node_group.nil? || n.node.nil? 8 | end 9 | NodeGroupClassMembership.all.each do |n| 10 | n.destroy if n.node_group.nil? || n.node_class.nil? 11 | end 12 | NodeGroupEdge.all.each do |n| 13 | n.destroy if n.to.nil? || n.from.nil? 14 | end 15 | end 16 | 17 | def self.down 18 | # Can't restore orphaned associations, but why would you want to? 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /db/migrate/20100810011613_change_report_report_field_size_to_be_larger.rb: -------------------------------------------------------------------------------- 1 | class ChangeReportReportFieldSizeToBeLarger < ActiveRecord::Migration[4.2] 2 | @postgres = ActiveRecord::Base.connection.adapter_name.downcase =~ /postgres/ 3 | 4 | def self.up 5 | # data type 'text' is unlimited in postgres 6 | unless @postgres 7 | count = Report.where(['length(reports.report) = ?', 65535]).delete_all 8 | if count > 0 9 | say "WARNING: Deleted #{count} invalid reports that were truncated by the database due to an earlier bug. Please import your reports again (see README for details) if you wish to have these deleted reports re-added to your database correctly." 10 | end 11 | 12 | say "Increasing column size of reports to avoid truncation problems:" 13 | change_column( :reports, :report, :mediumtext, :limit => 16.megabytes ) 14 | end 15 | end 16 | 17 | def self.down 18 | unless @postgres 19 | change_column( :reports, :report, :text ) 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /db/migrate/20100811204545_add_success_to_report_index.rb: -------------------------------------------------------------------------------- 1 | class AddSuccessToReportIndex < ActiveRecord::Migration[4.2] 2 | def self.up 3 | remove_index :reports, :node_id 4 | add_index :reports, [:node_id, :success] 5 | end 6 | 7 | def self.down 8 | remove_index :reports, [:node_id, :success] 9 | add_index :reports, :node_id 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20100916183948_adjust_indexes_on_reports.rb: -------------------------------------------------------------------------------- 1 | class AdjustIndexesOnReports < ActiveRecord::Migration[4.2] 2 | def self.up 3 | remove_index :reports, :time 4 | 5 | add_index :reports, [:time, :node_id, :success] 6 | end 7 | 8 | def self.down 9 | remove_index :reports, [:time, :node_id, :success] 10 | 11 | add_index :reports, :time 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20101109001012_add_status_to_reports.rb: -------------------------------------------------------------------------------- 1 | class AddStatusToReports < ActiveRecord::Migration[4.2] 2 | class Node < ActiveRecord::Base 3 | belongs_to :last_report, :class_name => 'Report' 4 | end 5 | 6 | def self.up 7 | add_column :reports, :status, :string 8 | add_index :reports, [:time, :node_id, :status] 9 | 10 | remove_index :reports, [:time, :node_id, :success] 11 | remove_column :reports, :success 12 | 13 | add_column :nodes, :status, :string 14 | remove_column :nodes, :success 15 | end 16 | 17 | def self.down 18 | add_column :reports, :success, :boolean 19 | add_index :reports, [:time, :node_id, :success] 20 | Report.update_all({:success => true}, "status != 'failed'") 21 | Report.update_all({:success => false}, "status = 'failed'") 22 | remove_index :reports, [:time, :node_id, :status] 23 | remove_column :reports, :status 24 | 25 | add_column :nodes, :success, :boolean, :default => false 26 | Node.all.each do |node| 27 | node.success = node.last_report ? node.last_report.success : false 28 | node.save 29 | end 30 | remove_column :nodes, :status 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /db/migrate/20101118222325_add_hidden_to_nodes.rb: -------------------------------------------------------------------------------- 1 | class AddHiddenToNodes < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :nodes, :hidden, :boolean, :default => false 4 | end 5 | 6 | def self.down 7 | remove_column :nodes, :hidden 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20101229023023_add_baseline_report_id_to_nodes.rb: -------------------------------------------------------------------------------- 1 | class AddBaselineReportIdToNodes < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :nodes, :baseline_report_id, :integer 4 | end 5 | 6 | def self.down 7 | remove_column :nodes, :baseline_report_id 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110105015322_add_out_of_sync_count_to_resource_statuses.rb: -------------------------------------------------------------------------------- 1 | class AddOutOfSyncCountToResourceStatuses < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :resource_statuses, :out_of_sync_count, :integer 4 | end 5 | 6 | def self.down 7 | remove_column :resource_statuses, :out_of_sync_count 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110105231637_remove_source_description_from_resource_statuses.rb: -------------------------------------------------------------------------------- 1 | class RemoveSourceDescriptionFromResourceStatuses < ActiveRecord::Migration[4.2] 2 | def self.up 3 | remove_column :resource_statuses, :source_description 4 | end 5 | 6 | def self.down 7 | add_column :resource_statuses, :source_description, :string 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110105231833_remove_source_description_from_resource_events.rb: -------------------------------------------------------------------------------- 1 | class RemoveSourceDescriptionFromResourceEvents < ActiveRecord::Migration[4.2] 2 | def self.up 3 | remove_column :resource_events, :source_description 4 | end 5 | 6 | def self.down 7 | add_column :resource_events, :source_description, :string 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110105233543_add_historical_value_to_resource_events.rb: -------------------------------------------------------------------------------- 1 | class AddHistoricalValueToResourceEvents < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :resource_events, :historical_value, :string 4 | end 5 | 6 | def self.down 7 | remove_column :resource_events, :historical_value 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110105233640_add_audited_to_resource_events.rb: -------------------------------------------------------------------------------- 1 | class AddAuditedToResourceEvents < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :resource_events, :audited, :boolean 4 | end 5 | 6 | def self.down 7 | remove_column :resource_events, :audited 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110105234202_remove_tags_from_resource_events.rb: -------------------------------------------------------------------------------- 1 | class RemoveTagsFromResourceEvents < ActiveRecord::Migration[4.2] 2 | def self.up 3 | remove_column :resource_events, :tags 4 | end 5 | 6 | def self.down 7 | add_column :resource_events, :tags, :string 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110106002514_add_skipped_to_resource_statuses.rb: -------------------------------------------------------------------------------- 1 | class AddSkippedToResourceStatuses < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :resource_statuses, :skipped, :boolean 4 | end 5 | 6 | def self.down 7 | remove_column :resource_statuses, :skipped 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110107233911_remove_out_of_sync_column.rb: -------------------------------------------------------------------------------- 1 | class RemoveOutOfSyncColumn < ActiveRecord::Migration[4.2] 2 | def self.up 3 | remove_column :resource_statuses, :out_of_sync 4 | end 5 | 6 | def self.down 7 | add_column :resource_statuses, :out_of_sync, :boolean 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110113013807_add_last_inspect_report_id_to_nodes.rb: -------------------------------------------------------------------------------- 1 | class AddLastInspectReportIdToNodes < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :nodes, :last_inspect_report_id, :integer 4 | end 5 | 6 | def self.down 7 | remove_column :nodes, :last_inspect_report_id 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110113183616_remove_unused_tables_and_models.rb: -------------------------------------------------------------------------------- 1 | class RemoveUnusedTablesAndModels < ActiveRecord::Migration[4.2] 2 | def self.up 3 | drop_table :assignments 4 | drop_table :services 5 | end 6 | 7 | def self.down 8 | create_table :assignments, :force => true do |t| 9 | t.integer :node_id 10 | t.integer :service_id 11 | t.datetime :created_at 12 | t.datetime :updated_at 13 | end 14 | 15 | create_table :services, :force => true do |t| 16 | t.string :name 17 | t.string :type 18 | t.text :description 19 | t.datetime :created_at 20 | t.datetime :updated_at 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /db/migrate/20110113195253_rename_column_last_report_id_to_last_apply_report_id_on_nodes.rb: -------------------------------------------------------------------------------- 1 | class RenameColumnLastReportIdToLastApplyReportIdOnNodes < ActiveRecord::Migration[4.2] 2 | def self.up 3 | rename_column :nodes, :last_report_id, :last_apply_report_id 4 | end 5 | 6 | def self.down 7 | rename_column :nodes, :last_apply_report_id, :last_report_id 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110114190814_add_failed_to_resource_statuses.rb: -------------------------------------------------------------------------------- 1 | class AddFailedToResourceStatuses < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :resource_statuses, :failed, :boolean 4 | end 5 | 6 | def self.down 7 | remove_column :resource_statuses, :failed 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110130010154_remove_column_baseline_report_id_from_nodes.rb: -------------------------------------------------------------------------------- 1 | class RemoveColumnBaselineReportIdFromNodes < ActiveRecord::Migration[4.2] 2 | def self.up 3 | remove_column :nodes, :baseline_report_id 4 | end 5 | 6 | def self.down 7 | add_column :nodes, :baseline_report_id, :integer 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110603183820_add_status_column_to_resource_statuses.rb: -------------------------------------------------------------------------------- 1 | class AddStatusColumnToResourceStatuses < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :resource_statuses, :status, :string 4 | 5 | # only going to update last report for each node since that's what people will care most about for counts 6 | # if users want all reports updated they can run the rake task 7 | Node.all.each do |n| 8 | last_report = n.last_apply_report 9 | next unless last_report 10 | last_report.munge 11 | last_report.save! 12 | end 13 | end 14 | 15 | def self.down 16 | remove_column :resource_statuses, :status 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /db/migrate/20110620111500_create_delayed_job_failures.rb: -------------------------------------------------------------------------------- 1 | class CreateDelayedJobFailures < ActiveRecord::Migration[4.2] 2 | def self.up 3 | create_table :delayed_job_failures do |t| 4 | t.string :summary, :limit => 255 5 | t.text :details 6 | t.boolean :read, :default => false, :null => false 7 | t.timestamps 8 | end 9 | end 10 | 11 | def self.down 12 | drop_table :delayed_job_failures 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20110728195829_add_node_host_uniqueness_constraint.rb: -------------------------------------------------------------------------------- 1 | class AddNodeHostUniquenessConstraint < ActiveRecord::Migration[4.2] 2 | def self.up 3 | execute <<-SQL 4 | ALTER TABLE nodes 5 | ADD CONSTRAINT uc_node_name UNIQUE (name) 6 | SQL 7 | end 8 | 9 | def self.down 10 | execute <<-SQL 11 | ALTER TABLE nodes 12 | DROP INDEX uc_node_name 13 | SQL 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20110729201310_add_delayed_job_failure_backtrace.rb: -------------------------------------------------------------------------------- 1 | class AddDelayedJobFailureBacktrace < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :delayed_job_failures, :backtrace, :text 4 | end 5 | 6 | def self.down 7 | remove_column :delayed_job_failures, :backtrace 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20111118204121_add_report_foreign_key_constraints.rb: -------------------------------------------------------------------------------- 1 | class AddReportForeignKeyConstraints < ActiveRecord::Migration[4.2] 2 | def self.up 3 | # Can't add constraints until we clean up 4 | Rake::Task['reports:prune:orphaned'].invoke 5 | 6 | sql = Proc.new {|table, foreign_key, references| 7 | foreign_key ||= 'report_id' 8 | references ||= 'reports' 9 | 10 | execute "ALTER TABLE #{table} ADD CONSTRAINT fk_#{table}_#{foreign_key} FOREIGN KEY (#{foreign_key}) REFERENCES #{references}(id) ON DELETE CASCADE;" 11 | } 12 | 13 | sql.call('reports', 'node_id', 'nodes') 14 | sql.call('resource_events', 'resource_status_id', 'resource_statuses') 15 | sql.call('resource_statuses') 16 | sql.call('report_logs') 17 | sql.call('metrics') 18 | end 19 | 20 | def self.down 21 | { 22 | :reports => 'node_id', 23 | :resource_events => 'resource_status_id', 24 | :resource_statuses => 'report_id', 25 | :report_logs => 'report_id', 26 | :metrics => 'report_id', 27 | }.each do |table, column_name| 28 | execute("ALTER TABLE #{table} DROP FOREIGN KEY fk_#{table}_#{column_name}") 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /db/migrate/20120112195235_remove_url_from_nodes.rb: -------------------------------------------------------------------------------- 1 | class RemoveUrlFromNodes < ActiveRecord::Migration[4.2] 2 | def self.up 3 | remove_column :nodes, :url 4 | end 5 | 6 | def self.down 7 | add_column :nodes, :url, :string 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20121111212016_add_queue_to_delayed_jobs.rb: -------------------------------------------------------------------------------- 1 | class AddQueueToDelayedJobs < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_column :delayed_jobs, :queue, :string 4 | end 5 | 6 | def self.down 7 | remove_column :delayed_jobs, :queue 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20130322105500_create_foreign_key_indexes.rb: -------------------------------------------------------------------------------- 1 | class CreateForeignKeyIndexes < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_index :node_group_memberships, :node_group_id 4 | add_index :node_group_memberships, :node_id 5 | add_index :node_group_class_memberships, :node_group_id 6 | add_index :node_group_class_memberships, :node_class_id 7 | add_index :node_class_memberships, :node_id 8 | add_index :node_class_memberships, :node_class_id 9 | add_index :node_group_edges, :from_id 10 | add_index :node_group_edges, :to_id 11 | add_index :parameters, [:parameterable_type, :parameterable_id] 12 | end 13 | 14 | def self.down 15 | remove_index :node_group_memberships, :node_group_id 16 | remove_index :node_group_memberships, :node_id 17 | remove_index :node_group_class_memberships, :node_group_id 18 | remove_index :node_group_class_memberships, :node_class_id 19 | remove_index :node_class_memberships, :node_id 20 | remove_index :node_class_memberships, :node_class_id 21 | remove_index :node_group_edges, :from_id 22 | remove_index :node_group_edges, :to_id 23 | remove_index :parameters, [:parameterable_type, :parameterable_id] 24 | end 25 | end -------------------------------------------------------------------------------- /db/migrate/20130418063629_add_description_to_node_classes.rb: -------------------------------------------------------------------------------- 1 | class AddDescriptionToNodeClasses < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :node_classes, :description, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130418064011_add_description_to_node_groups.rb: -------------------------------------------------------------------------------- 1 | class AddDescriptionToNodeGroups < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :node_groups, :description, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20140118072510_add_performance_indices.rb: -------------------------------------------------------------------------------- 1 | class AddPerformanceIndices < ActiveRecord::Migration[4.2] 2 | def self.up 3 | add_index :timeline_events, [:subject_id, :subject_type], :name => 'index_timeline_events_primary' 4 | add_index :timeline_events, [:secondary_subject_id, :secondary_subject_type], :name => 'index_timeline_events_secondary' 5 | add_index :metrics, [:report_id, :category, :name], :name => 'index_metrics_multi' 6 | add_index :nodes, :last_apply_report_id 7 | add_index :parameters, [:parameterable_id, :parameterable_type, :key], :name => 'index_parameters_multi' 8 | add_index :delayed_jobs, [:failed_at, :run_at, :locked_at, :locked_by], :name => 'index_delayed_jobs_multi' 9 | end 10 | 11 | def self.down 12 | remove_index :delayed_jobs, :name => 'index_delayed_jobs_multi' 13 | remove_index :parameters, :name => 'index_parameters_multi' 14 | remove_index :nodes, :last_apply_report_id 15 | remove_index :metrics, :name => 'index_metrics_multi' 16 | remove_index :timeline_events, :name => 'index_timeline_events_secondary' 17 | remove_index :timeline_events, :name => 'index_timeline_events_primary' 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /db/migrate/20140414051338_change_reports_to_blobs.rb: -------------------------------------------------------------------------------- 1 | class ChangeReportsToBlobs < ActiveRecord::Migration[4.2] 2 | def up 3 | if ActiveRecord::Base.connection.adapter_name.downcase =~ /postgres/ 4 | # bytea columns are unlimited 5 | change_column :resource_events, :message, 'bytea USING message::bytea' 6 | change_column :delayed_jobs, :handler, 'bytea USING handler::bytea' 7 | change_column :delayed_job_failures, :details, 'bytea USING details::bytea' 8 | else 9 | # Lenghts > 16MB are LONGBLOB 10 | change_column :resource_events, :message, :binary, :limit => 20.megabyte 11 | change_column :delayed_jobs, :handler, :binary, :limit => 20.megabyte 12 | change_column :delayed_job_failures, :details, :binary, :limit => 20.megabyte 13 | end 14 | end 15 | 16 | # This is not likely to work. Best not to reverse this. 17 | def down 18 | # change_column :resource_events, :message, :text 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /db/migrate/20141217071943_add_environment_to_nodes.rb: -------------------------------------------------------------------------------- 1 | class AddEnvironmentToNodes < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :nodes, :environment, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20150405234511_add_environment_to_reports.rb: -------------------------------------------------------------------------------- 1 | class AddEnvironmentToReports < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :reports, :environment, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20150406035502_add_transaction_uuid_to_reports.rb: -------------------------------------------------------------------------------- 1 | class AddTransactionUuidToReports < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :reports, :transaction_uuid, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20150406035704_add_containment_path_to_resource_statuses.rb: -------------------------------------------------------------------------------- 1 | class AddContainmentPathToResourceStatuses < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :resource_statuses, :containment_path, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180612210108_add_catalog_uuid_to_reports.rb: -------------------------------------------------------------------------------- 1 | class AddCatalogUuidToReports < ActiveRecord::Migration[5.2] 2 | def change 3 | add_column :reports, :catalog_uuid, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180612210310_add_cached_catalog_status_to_reports.rb: -------------------------------------------------------------------------------- 1 | class AddCachedCatalogStatusToReports < ActiveRecord::Migration[5.2] 2 | def change 3 | add_column :reports, :cached_catalog_status, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180613224704_add_report_format6.rb: -------------------------------------------------------------------------------- 1 | class AddReportFormat6 < ActiveRecord::Migration[5.2] 2 | def change 3 | add_column :reports, :noop, :boolean 4 | add_column :reports, :noop_pending, :boolean 5 | add_column :reports, :corrective_change, :boolean 6 | add_column :reports, :master_used, :string 7 | 8 | add_column :resource_statuses, :corrective_change, :boolean 9 | 10 | add_column :resource_events, :corrective_change, :boolean 11 | add_column :resource_events, :redacted, :boolean 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20180614161626_add_report_format8.rb: -------------------------------------------------------------------------------- 1 | class AddReportFormat8 < ActiveRecord::Migration[5.2] 2 | def change 3 | add_column :reports, :transaction_completed, :boolean 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180614210435_add_report_format9.rb: -------------------------------------------------------------------------------- 1 | class AddReportFormat9 < ActiveRecord::Migration[5.2] 2 | def change 3 | add_column :resource_statuses, :provider_used, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /docs/manual/images/background_tasks_pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/docs/manual/images/background_tasks_pending.png -------------------------------------------------------------------------------- /docs/manual/index.markdown: -------------------------------------------------------------------------------- 1 | Puppet Dashboard Manual 2 | ===== 3 | 4 | This is the manual for Puppet Dashboard. 5 | 6 | Overview 7 | -------- 8 | 9 | Puppet Dashboard is a web interface for Puppet. It can view and analyze Puppet reports, assign Puppet classes and parameters to nodes, and view inventory data and backed-up file contents. 10 | 11 | Chapters 12 | -------- 13 | 14 | * [Installing Dashboard](./bootstrapping.markdown) 15 | * [Upgrading Dashboard](./upgrading.markdown) 16 | * [Configuring Dashboard](./configuring.markdown) 17 | * [Maintaining Dashboard](./maintaining.markdown) 18 | * [Rake API](./rake_api.markdown) 19 | -------------------------------------------------------------------------------- /ext/build_defaults.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | packaging_url: 'git://github.com/puppetlabs/packaging.git --branch=master' 3 | packaging_repo: 'packaging' 4 | default_cow: 'base-squeeze-i386.cow' 5 | cows: 'base-lucid-i386.cow base-precise-i386.cow base-quantal-i386.cow base-raring-i386.cow base-sid-i386.cow base-squeeze-i386.cow base-stable-i386.cow base-testing-i386.cow base-unstable-i386.cow base-wheezy-i386.cow' 6 | pbuild_conf: '/etc/pbuilderrc' 7 | packager: 'puppetlabs' 8 | gpg_name: 'info@puppetlabs.com' 9 | gpg_key: '4BD6EC30' 10 | sign_tar: FALSE 11 | # a space separated list of mock configs 12 | final_mocks: 'pl-el-5-i386 pl-el-6-i386' 13 | yum_host: 'burji.puppetlabs.com' 14 | yum_repo_path: '/opt/repository/yum/' 15 | build_gem: FALSE 16 | build_dmg: FALSE 17 | apt_host: 'burji.puppetlabs.com' 18 | apt_repo_url: 'http://apt.puppetlabs.com' 19 | apt_repo_path: '/opt/repository/incoming' 20 | pre_tar_task: 'package:vendor_gems' 21 | -------------------------------------------------------------------------------- /ext/debian/README.Debian: -------------------------------------------------------------------------------- 1 | Puppet Dashboard for Debian 2 | =========================== 3 | 4 | Overview 5 | -------- 6 | 7 | This package installs the Puppet Dashboard into `/usr/share/puppet-dashboard` -- this directory will be referred to as the "Puppet Dashboard directory" throughout this document. 8 | 9 | Please also read the general usage and installation instructions in the `README.markdown` file in the Puppet Dashboard directory. 10 | 11 | Installation 12 | ------------ 13 | 14 | 1. Install a MySQL server if you don't already have one, e.g.: 15 | 16 | sudo apt-get install mysql-server 17 | 18 | 1. Create an `/etc/puppet-dashboard/database.yml` file. Please see `/usr/share/doc/puppet-dashboard/examples/database.yml.example` for an example. 19 | 20 | 2. Create the database by running the following commands from the Puppet Dashboard directory: 21 | 22 | rake RAILS_ENV=production db:create 23 | 24 | 3. Apply the database migrations by running the following commands from the Puppet Dashboard directory, you will need to do this after upgrading to a new release: 25 | 26 | rake RAILS_ENV=production db:migrate 27 | 28 | 4. Start the Puppet Dashboard server: 29 | 30 | sudo service puppet-dashboard start 31 | -------------------------------------------------------------------------------- /ext/debian/compat: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /ext/debian/conf/database.yml.template: -------------------------------------------------------------------------------- 1 | production: 2 | adapter: _DBC_DBTYPE_ 3 | database: _DBC_DBNAME_ 4 | host: _DBC_DBSERVER_ 5 | port: _DBC_DBPORT_ 6 | username: _DBC_DBUSER_ 7 | password: _DBC_DBPASS_ 8 | encoding: utf8 9 | -------------------------------------------------------------------------------- /ext/debian/control: -------------------------------------------------------------------------------- 1 | Source: puppet-dashboard 2 | Section: web 3 | Priority: extra 4 | Maintainer: James Turnbull 5 | Build-Depends: debhelper (>= 7), cdbs 6 | Build-Depends-Indep: po-debconf 7 | Standards-Version: 3.8.4 8 | Homepage: http://github.com/puppetlabs/puppet-dashboard 9 | 10 | Package: puppet-dashboard 11 | Architecture: all 12 | Pre-Depends: debconf 13 | Depends: ruby, ruby1.8 (>= 1.8.7), rake (>=0.8.3), dbconfig-common, libdbd-mysql-ruby, mysql-client, rubygems, libhttpclient-ruby1.8 14 | Suggests: mysql-server 15 | Recommends: libapache2-mod-passenger 16 | Description: Dashboard for Puppet 17 | The Puppet Dashboard is a web application for managing the Puppet configuration 18 | management tool. 19 | 20 | -------------------------------------------------------------------------------- /ext/debian/default: -------------------------------------------------------------------------------- 1 | # IMPORTANT: Be sure you have checked the values below, appropriately 2 | # configured 'config/database.yml' in your DASHBOARD_HOME, and 3 | # created and migrated the database. 4 | 5 | # Uncomment the line below to start Puppet Dashboard. 6 | ### START=yes 7 | 8 | # Location where puppet-dashboard is installed: 9 | DASHBOARD_HOME=/usr/share/puppet-dashboard 10 | 11 | # User which runs the puppet-dashboard program: 12 | DASHBOARD_USER=www-data 13 | 14 | # Ruby version to run the puppet-dashboard as: 15 | DASHBOARD_RUBY=/usr/bin/ruby 16 | 17 | # Rails environment in which puppet-dashboard runs: 18 | DASHBOARD_ENVIRONMENT=production 19 | 20 | # Network interface which puppet-dashboard web server is running at: 21 | DASHBOARD_IFACE=0.0.0.0 22 | 23 | # Port on which puppet-dashboard web server is running at, note that if the 24 | # puppet-dashboard user is not root, it has to be a > 1024: 25 | DASHBOARD_PORT=3000 26 | -------------------------------------------------------------------------------- /ext/debian/dirs: -------------------------------------------------------------------------------- 1 | usr/share/puppet-dashboard/log 2 | usr/share/puppet-dashboard/tmp 3 | usr/share/puppet-dashboard/spool 4 | 5 | -------------------------------------------------------------------------------- /ext/debian/doc/examples/apache2-alias.conf: -------------------------------------------------------------------------------- 1 | # These modules must be enabled : rewrite, fcgid 2 | # (mod_fastcgi is much harder to configure) 3 | # Configuration for http://localhost/puppet-dashboard 4 | 5 | # DefaultInitEnv for module mod_fcgid 6 | DefaultInitEnv RAILS_RELATIVE_URL_ROOT "/puppet-dashboard" 7 | DefaultInitEnv X_DEBIAN_SITEID "default" 8 | 9 | # the mod_fcgid socket path 10 | SocketPath "/var/run/puppet-dashboard/sockets/default" 11 | 12 | Alias "/puppet-dashboard/plugin_assets/" /var/cache/puppet-dashboard/default/plugin_assets/ 13 | Alias "/puppet-dashboard" /usr/share/puppet-dashboard/public 14 | 15 | Options +FollowSymLinks +ExecCGI 16 | Order allow,deny 17 | Allow from all 18 | RewriteEngine On 19 | RewriteBase "/puppet-dashboard" 20 | RewriteRule ^$ index.html [QSA] 21 | RewriteRule ^([^.]+)$ $1.html [QSA] 22 | RewriteCond %{REQUEST_FILENAME} !-f [OR] 23 | RewriteCond %{REQUEST_FILENAME} dispatch.fcgi$ 24 | RewriteRule ^(.*)$ dispatch.fcgi [QSA,L] 25 | 26 | 27 | -------------------------------------------------------------------------------- /ext/debian/doc/examples/apache2-host.conf: -------------------------------------------------------------------------------- 1 | # These modules must be enabled : rewrite, fcgid 2 | # (mod_fastcgi is much harder to configure) 3 | # Configuration for http://localhost:8080 4 | 5 | # DefaultInitEnv for module mod_fcgid 6 | DefaultInitEnv RAILS_RELATIVE_URL_ROOT "" 7 | DefaultInitEnv X_DEBIAN_SITEID "default" 8 | 9 | # the mod_fcgid socket path 10 | SocketPath "/var/run/puppet-dashboard/sockets/default" 11 | Alias "/plugin_assets/" /var/cache/puppet-dashboard/default/plugin_assets/ 12 | DocumentRoot /usr/share/puppet-dashboard/public 13 | 14 | Options +FollowSymLinks +ExecCGI 15 | Order allow,deny 16 | Allow from all 17 | RewriteEngine On 18 | RewriteRule ^$ index.html [QSA] 19 | RewriteRule ^([^.]+)$ $1.html [QSA] 20 | RewriteCond %{REQUEST_FILENAME} !-f [OR] 21 | RewriteCond %{REQUEST_FILENAME} dispatch.fcgi$ 22 | RewriteRule ^(.*)$ dispatch.fcgi [QSA,L] 23 | 24 | 25 | -------------------------------------------------------------------------------- /ext/debian/doc/examples/apache2-passenger.conf: -------------------------------------------------------------------------------- 1 | # These modules must be enabled : passenger 2 | # Configuration for http://localhost/puppet-dashboard 3 | 4 | # this is the passenger config 5 | RailsEnv production 6 | RailsBaseURI /puppet-dashboard 7 | SetEnv X_DEBIAN_SITEID "default" 8 | Alias "/puppet-dashboard/plugin_assets/" /var/cache/puppet-dashboard./default/plugin_assets/ 9 | DocumentRoot /usr/share/puppet-dashboard/public 10 | 11 | Order allow,deny 12 | Allow from all 13 | 14 | 15 | -------------------------------------------------------------------------------- /ext/debian/docs: -------------------------------------------------------------------------------- 1 | debian/doc/examples 2 | -------------------------------------------------------------------------------- /ext/debian/files: -------------------------------------------------------------------------------- 1 | puppet-dashboard_1.0.3_all.deb web extra 2 | -------------------------------------------------------------------------------- /ext/debian/install: -------------------------------------------------------------------------------- 1 | # Install the basic application files 2 | app usr/share/puppet-dashboard 3 | config usr/share/puppet-dashboard 4 | db usr/share/puppet-dashboard 5 | ext usr/share/puppet-dashboard 6 | lib usr/share/puppet-dashboard 7 | public usr/share/puppet-dashboard 8 | LICENSE usr/share/puppet-dashboard 9 | README.markdown usr/share/puppet-dashboard 10 | README_PACKAGES.markdown usr/share/puppet-dashboard 11 | Rakefile usr/share/puppet-dashboard 12 | script usr/share/puppet-dashboard 13 | spec usr/share/puppet-dashboard 14 | vendor/plugins usr/share/puppet-dashboard/vendor 15 | vendor/gems usr/share/puppet-dashboard/vendor 16 | vendor/rails usr/share/puppet-dashboard/vendor 17 | debian/conf/*.template usr/share/puppet-dashboard/templates 18 | -------------------------------------------------------------------------------- /ext/debian/logrotate: -------------------------------------------------------------------------------- 1 | # Puppet-Dashboard logs: 2 | /var/log/puppet-dashboard/*/*.log { 3 | daily 4 | missingok 5 | rotate 14 6 | compress 7 | delaycompress 8 | notifempty 9 | copytruncate 10 | } 11 | -------------------------------------------------------------------------------- /ext/debian/po/templates.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PACKAGE VERSION\n" 9 | "Report-Msgid-Bugs-To: info@puppetlabs.com\n" 10 | "POT-Creation-Date: 2010-03-25 21:09+1100\n" 11 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language-Team: LANGUAGE \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=CHARSET\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | -------------------------------------------------------------------------------- /ext/debian/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | if [ "$1" = "purge" ]; then 4 | if test -d /usr/share/puppet-dashboard; then 5 | rm -rf /usr/share/puppet-dashboard 6 | fi 7 | fi 8 | 9 | #DEBHELPER# 10 | -------------------------------------------------------------------------------- /ext/debian/puppet-dashboard-workers.default: -------------------------------------------------------------------------------- 1 | # IMPORTANT: Be sure you have checked the values below, appropriately 2 | # configured 'config/database.yml' in your DASHBOARD_HOME, and 3 | # created and migrated the database. 4 | . /etc/default/puppet-dashboard 5 | ### START=no 6 | 7 | # Number of dashboard workers to start. This will be the number of jobs that 8 | # can be concurrently processed. A simple recommendation would be to start 9 | # with the number of cores you have available. 10 | NUM_DELAYED_JOB_WORKERS=2 11 | -------------------------------------------------------------------------------- /ext/debian/rmshebang.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | for target_dir in $@ 4 | do 5 | for f in `find "$target_dir" -type f 2>/dev/null` 6 | do 7 | sed -e '1,1{ 8 | /^#!/d 9 | }' < $f > $f.tmp 10 | if ! cmp $f $f.tmp >/dev/null 11 | then 12 | mv -f $f.tmp $f 13 | else 14 | rm -f $f.tmp 15 | fi 16 | done 17 | done 18 | -------------------------------------------------------------------------------- /ext/debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /ext/project_data.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | project: 'puppet-dashboard' 3 | author: 'Puppet Labs' 4 | email: 'info@puppetlabs.com' 5 | homepage: 'https://github.com/puppetlabs/puppet-dashboard' 6 | summary: 'The Puppet Dashboard is a web application for managing the Puppet configuration management tool.' 7 | description: 'Puppet Dashboard is a systems management web application for managing Puppet installations and is written using the Ruby on Rails framework.' 8 | version_file: 'VERSION' 9 | # files and gem_files are space separated lists 10 | files: 'acceptance app bin config db examples ext lib log public script spec spool tmp vendor CONTRIBUTING.md LICENSE PLUGINS.md README.markdown README_PACKAGES.markdown Rakefile SELENIUM.md VERSION' 11 | -------------------------------------------------------------------------------- /ext/puppet/puppet_dashboard.rb: -------------------------------------------------------------------------------- 1 | require 'puppet' 2 | 3 | HOST = 'localhost' 4 | PORT = 3000 5 | 6 | Puppet::Reports.register_report(:puppet_dashboard) do 7 | desc "Send report information to Puppet-Dashboard" 8 | 9 | def process 10 | Net::HTTP.start(HOST, PORT) do |conn| 11 | conn.post "/reports/upload", "report=" + CGI.escape(self.to_yaml) 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /ext/redhat/puppet-dashboard-workers.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Puppet Dashboard background workers 3 | After=httpd.service syslog.target 4 | 5 | [Service] 6 | # Default values 7 | Environment="WORKERS=2" 8 | Environment="RAILS_ENV=production" 9 | Environment="DASHBOARD_HOME=/usr/share/puppet-dashboard" 10 | # Overrides here 11 | EnvironmentFile=-/etc/sysconfig/puppet-dashboard 12 | EnvironmentFile=-/etc/sysconfig/puppet-dashboard-workers 13 | # 14 | Type=forking 15 | Restart=always 16 | ExecStart=/bin/ruby ${DASHBOARD_HOME}/script/delayed_job -p dashboard -n ${WORKERS} -m start 17 | ExecStop=/bin/ruby ${DASHBOARD_HOME}/script/delayed_job -p dashboard -n ${WORKERS} -m stop 18 | User=puppet-dashboard 19 | SyslogIdentifier=puppet-dashboard 20 | NoNewPrivileges=true 21 | 22 | [Install] 23 | WantedBy=multi-user.target 24 | -------------------------------------------------------------------------------- /ext/redhat/puppet-dashboard.logrotate: -------------------------------------------------------------------------------- 1 | # Rotate puppet-dashboard logs 2 | /usr/share/puppet-dashboard/log/*.log { 3 | daily 4 | missingok 5 | rotate 7 6 | compress 7 | delaycompress 8 | notifempty 9 | copytruncate 10 | } 11 | -------------------------------------------------------------------------------- /ext/redhat/puppet-dashboard.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Puppet Dashboard 3 | After=httpd.service syslog.target 4 | 5 | [Service] 6 | # Default values 7 | Environment="RAILS_ENV=production" 8 | Environment="DASHBOARD_HOME=/usr/share/puppet-dashboard" 9 | # Overrides here 10 | EnvironmentFile=-/etc/sysconfig/puppet-dashboard 11 | # 12 | Type=forking 13 | Restart=always 14 | ExecStart=/bin/ruby ${DASHBOARD_HOME}/script/rails server -e ${DASHBOARD_ENVIRONMENT} -p ${DASHBOARD_PORT} -b ${DASHBOARD_IFACE} 15 | KillSignal=SIGINT 16 | User=puppet-dashboard 17 | SyslogIdentifier=puppet-dashboard 18 | NoNewPrivileges=true 19 | 20 | [Install] 21 | WantedBy=multi-user.target 22 | -------------------------------------------------------------------------------- /ext/redhat/puppet-dashboard.sysconfig: -------------------------------------------------------------------------------- 1 | # 2 | # path to where you installed puppet dashboard 3 | # 4 | DASHBOARD_HOME=/usr/share/puppet-dashboard 5 | DASHBOARD_USER=puppet-dashboard 6 | DASHBOARD_RUBY=/usr/bin/ruby 7 | DASHBOARD_ENVIRONMENT=production 8 | DASHBOARD_IFACE=0.0.0.0 9 | DASHBOARD_PORT=3000 10 | -------------------------------------------------------------------------------- /ext/redhat/systemd-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | DIR=$(dirname $0) 3 | cp ${DIR}/puppet-dashboard.service /etc/systemd/system/ 4 | cp ${DIR}/puppet-dashboard-workers.service /etc/systemd/system/ 5 | systemctl daemon-reload 6 | -------------------------------------------------------------------------------- /lib/add_renderers.rb: -------------------------------------------------------------------------------- 1 | # This is straight out of the comments in actionpack/lib/action_controller/metal/renderers.rb 2 | ActionController::Renderers.add :csv do |obj, options| 3 | filename = options[:filename] || 'data' 4 | str = obj.respond_to?(:to_csv) ? obj.to_csv : obj.to_s 5 | send_data str, :type => Mime[:csv], 6 | :disposition => "attachment; filename=#{filename}.csv" 7 | end 8 | 9 | ActionController::Renderers.add :yaml do |obj, options| 10 | str = obj.respond_to?(:to_yaml) ? obj.to_yaml : obj.to_s 11 | send_data str, :type => Mime[:yaml] 12 | end 13 | -------------------------------------------------------------------------------- /lib/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/lib/assets/.gitkeep -------------------------------------------------------------------------------- /lib/class_parameter_conflict_error.rb: -------------------------------------------------------------------------------- 1 | class ClassParameterConflictError < StandardError 2 | end 3 | -------------------------------------------------------------------------------- /lib/csv_extensions.rb: -------------------------------------------------------------------------------- 1 | # In Ruby 1.9 and up, FasterCSV is in stdlib and is called CSV. 2 | if RUBY_VERSION < '1.9' 3 | require 'fastercsv' 4 | CSV = FasterCSV 5 | else 6 | require 'csv' 7 | end 8 | 9 | class Array 10 | def to_csv 11 | header = first.class.to_csv_header if first.class.respond_to?(:to_csv_header) 12 | lines = map(&:to_csv) 13 | lines.unshift header if header 14 | lines.join 15 | end 16 | end 17 | 18 | class ActiveRecord::Base 19 | def self.to_csv_properties 20 | column_names 21 | end 22 | 23 | def self.to_csv_header 24 | CSV.generate_line to_csv_properties 25 | end 26 | 27 | def to_csv_array 28 | self.class.to_csv_properties.map {|prop| self.send(prop)} 29 | end 30 | 31 | def to_csv 32 | CSV.generate_line to_csv_array 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/find_by_id_or_name.rb: -------------------------------------------------------------------------------- 1 | module FindByIdOrName 2 | def find_by_id_or_name!(identifier) 3 | case identifier 4 | when Integer, /^\d+$/ 5 | find_by_id!(identifier) 6 | else 7 | find_by_name!(identifier) 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/has_parameters.rb: -------------------------------------------------------------------------------- 1 | module HasParameters 2 | def self.included(klass) 3 | klass.extend(ClassMethods) 4 | end 5 | 6 | module ClassMethods 7 | def has_parameters(options={}) 8 | 9 | include HasParameters::InstanceMethods 10 | 11 | has_many :parameters, {:as => :parameterable, :dependent => :destroy}.merge(options) do 12 | def to_hash 13 | Hash[*to_a.map{|p| [p.key, p.value]}.flatten] 14 | end 15 | end 16 | end 17 | end 18 | 19 | module InstanceMethods 20 | def parameter_attributes=(values) 21 | raise NodeClassificationDisabledError.new unless SETTINGS.use_external_node_classification 22 | new_parameters = values.reject{|v| v[:key].blank? && v[:value].blank?}.map do |hash| 23 | parameter = parameters.find_or_initialize_by(key: hash[:key]) 24 | parameter.value = hash[:value] 25 | parameter.save 26 | parameter 27 | end 28 | self.parameters = new_parameters 29 | end 30 | end 31 | end 32 | 33 | ActiveRecord::Base.send(:include, HasParameters) 34 | -------------------------------------------------------------------------------- /lib/incorrect_report_kind.rb: -------------------------------------------------------------------------------- 1 | class IncorrectReportKind < StandardError 2 | end 3 | -------------------------------------------------------------------------------- /lib/node_classification_disabled_error.rb: -------------------------------------------------------------------------------- 1 | class NodeClassificationDisabledError < StandardError 2 | end 3 | -------------------------------------------------------------------------------- /lib/parameter_conflict_error.rb: -------------------------------------------------------------------------------- 1 | class ParameterConflictError < StandardError 2 | end 3 | -------------------------------------------------------------------------------- /lib/read_only_enabled_error.rb: -------------------------------------------------------------------------------- 1 | class ReadOnlyEnabledError < StandardError 2 | end 3 | -------------------------------------------------------------------------------- /lib/tasks/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/lib/tasks/.gitkeep -------------------------------------------------------------------------------- /lib/tasks/clean_sample_reports.rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'fileutils' 4 | require 'data_generator' 5 | 6 | namespace :reports do 7 | namespace :samples do 8 | 9 | desc "Remove previously generated sample reports." 10 | task :clean do 11 | report_dir = 'tmp/sample_reports' 12 | 13 | FileUtils.rm_rf(report_dir) 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/tasks/generate_and_import_samples.rake: -------------------------------------------------------------------------------- 1 | namespace :reports do 2 | namespace :samples do 3 | desc "Generate sample YAML reports and import them into the database" 4 | task :populate => [:clean, :generate, 'reports:import'] 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /lib/tasks/generate_unresponsive_nodes.rake: -------------------------------------------------------------------------------- 1 | require 'data_generator' 2 | 3 | namespace :node do 4 | desc "Generate NUM_NODES unresponsive nodes with random hostnames for testing" 5 | task :generate_unresponsive => :environment do 6 | num_nodes = ENV['NUM_NODES'].to_i || 1 7 | 8 | num_nodes.times do 9 | Node.create!(:name => DataGenerator.generate_hostname) 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/tasks/install_cleanup_cron.rake: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | namespace :cron do 3 | desc 'Install monthly cron job to automatically prune old reports from the databases.' 4 | task :cleanup do 5 | cron_path = '/etc/cron.monthly' 6 | dashboard_path = '/usr/share/puppet-dashboard/examples' 7 | cron_script = 'puppet-dashboard.cleanup_reports.cron' 8 | 9 | begin 10 | ln_sf("#{dashboard_path}/#{cron_script}", "#{cron_path}/#{cron_script}") 11 | rescue 12 | puts "\n\nError: Could not create symlink #{cron_path}/#{cron_script}\n" 13 | puts "Are you root?\n" 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/tasks/rake_helpers.rb: -------------------------------------------------------------------------------- 1 | # Common functions used by rake tasks 2 | 3 | def get_node(node_name) 4 | begin 5 | node = Node.find_by(name: node_name) 6 | unless node 7 | $stderr.puts "Node #{node_name} doesn't exist!" 8 | exit 1 9 | end 10 | rescue NameError 11 | $stderr.puts 'Must specify node name (name=).' 12 | exit 1 13 | rescue => e 14 | $stderr.puts "There was a problem finding the node: #{e.message}" 15 | exit 1 16 | end 17 | node 18 | end 19 | 20 | def get_group(group_name) 21 | group = NodeGroup.find_by(name: group_name) 22 | unless group 23 | $stderr.puts "Node group #{group_name} doesn't exist!" 24 | exit 1 25 | end 26 | group 27 | rescue NameError 28 | $stderr.puts 'Must specify node group name (name=).' 29 | exit 1 30 | rescue => e 31 | $stderr.puts "There was a problem finding the node group: #{e.message}" 32 | exit 1 33 | end 34 | 35 | def get_class(class_name) 36 | nodeclass = NodeClass.find_by(name: class_name) 37 | unless nodeclass 38 | $stderr.puts "Node class #{class_name} doesn't exist!" 39 | exit 1 40 | end 41 | nodeclass 42 | rescue NameError 43 | $stderr.puts 'Must specify node class name (name=).' 44 | exit 1 45 | rescue => e 46 | $stderr.puts "There was a problem finding the node class: #{e.message}" 47 | exit 1 48 | end 49 | 50 | -------------------------------------------------------------------------------- /lib/tasks/schematize_reports.rake: -------------------------------------------------------------------------------- 1 | namespace :reports do 2 | desc 'Migrate old reports to the new reports schema in reverse chronological order' 3 | task :schematize => :environment do 4 | 5 | class OldReport < ActiveRecord::Base 6 | end 7 | 8 | old_report_count = OldReport.count 9 | 10 | puts 11 | puts "Beginning to migrate #{old_report_count} reports" 12 | puts "Type Ctrl+c at any time to interrupt the migration" 13 | puts "Restarting the migration will resume where you left off" 14 | puts 15 | 16 | pbar = ProgressBar.create(title: 'Migrating', total: old_report_count) 17 | 18 | while OldReport.count > 0 do 19 | # Doing records in groups of 10_000 since finding all with millions at once takes forever and eats memory 20 | OldReport.all.limit(10_000).order('time desc').to_a.each do |report| 21 | ActiveRecord::Base.transaction do 22 | Report.create_from_yaml(report.report) 23 | report.destroy 24 | end 25 | pbar.increment 26 | end 27 | end 28 | pbar.finish 29 | 30 | end 31 | end 32 | 33 | -------------------------------------------------------------------------------- /lib/tasks/scss.rake: -------------------------------------------------------------------------------- 1 | desc "Compile application.scss to STDOUT" 2 | task :scss do 3 | sh "sass public/stylesheets/sass/application.scss" 4 | end 5 | -------------------------------------------------------------------------------- /lib/tasks/timeline.rake: -------------------------------------------------------------------------------- 1 | namespace :timeline do 2 | desc 'View event timeline' 3 | task :view => :environment do 4 | TimelineEvent.recent.each do |event| 5 | puts "%s %s %s was %s by %s" % [ 6 | event.created_at, 7 | event.subject_type, 8 | event.subject.name, 9 | event.event_type, 10 | event.actor_id, 11 | ] 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/tasks/update_report_data.rake: -------------------------------------------------------------------------------- 1 | namespace :reports do 2 | desc 'Performs updates to the reports that are specific to dashboard and not in the Puppet Report Format' 3 | task :update_report_data => :environment do 4 | report_count = Report.count 5 | 6 | pbar = ProgressBar.create(title: 'Updating', total: report_count) 7 | 8 | offset = 0 9 | 10 | # Doing records in groups of 1_000 since finding all with millions at once takes forever and eats memory 11 | while offset < Report.count 12 | Report.all.limit(1_000).offset(offset).order('time desc').to_a.each do |report| 13 | report.munge 14 | report.save! 15 | 16 | pbar.increment 17 | offset += 1 18 | end 19 | end 20 | 21 | pbar.finish 22 | 23 | end 24 | end 25 | 26 | -------------------------------------------------------------------------------- /lib/trimmer.rb: -------------------------------------------------------------------------------- 1 | module Trimmer 2 | def self.included(base) 3 | base.extend ClassMethods 4 | end 5 | 6 | module ClassMethods 7 | def trimmed_fields *field_list 8 | before_validation do |model| 9 | field_list.each do |n| 10 | model[n] = model[n].strip if model[n].respond_to?('strip') 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /log/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/log/.gitignore -------------------------------------------------------------------------------- /log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/log/.gitkeep -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 18 | 19 | 20 | 21 | 22 |
23 |

The page you were looking for doesn't exist.

24 |

You may have mistyped the address or the page may have moved.

25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 18 | 19 | 20 | 21 | 22 |
23 |

The change you wanted was rejected.

24 |

Maybe you tried to change something you didn't have access to.

25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Puppet Dashboard encountered an error (500) 5 | 6 | 18 | 19 | 20 | 21 | 22 |
23 |

Puppet Dashboard encountered an error.

24 |

Something went wrong, and Puppet Dashboard was unable to render the requested page. Please contact your site’s help desk or systems administrator; if that happens to be you, please check Dashboard’s logs for more information.

25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/favicon.ico -------------------------------------------------------------------------------- /public/images/close.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/close.gif -------------------------------------------------------------------------------- /public/images/dashboard_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/dashboard_logo.png -------------------------------------------------------------------------------- /public/images/icons/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/add.png -------------------------------------------------------------------------------- /public/images/icons/add_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/add_grey.png -------------------------------------------------------------------------------- /public/images/icons/add_light_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/add_light_grey.png -------------------------------------------------------------------------------- /public/images/icons/bullet_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/bullet_green.png -------------------------------------------------------------------------------- /public/images/icons/bullet_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/bullet_red.png -------------------------------------------------------------------------------- /public/images/icons/bullet_toggle_minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/bullet_toggle_minus.png -------------------------------------------------------------------------------- /public/images/icons/bullet_toggle_plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/bullet_toggle_plus.png -------------------------------------------------------------------------------- /public/images/icons/cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/cancel.png -------------------------------------------------------------------------------- /public/images/icons/changed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/changed.png -------------------------------------------------------------------------------- /public/images/icons/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/close.png -------------------------------------------------------------------------------- /public/images/icons/computer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/computer.png -------------------------------------------------------------------------------- /public/images/icons/delayed-job-failure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/delayed-job-failure.png -------------------------------------------------------------------------------- /public/images/icons/delayed-job-ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/delayed-job-ok.png -------------------------------------------------------------------------------- /public/images/icons/delayed-job-warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/delayed-job-warning.png -------------------------------------------------------------------------------- /public/images/icons/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/delete.png -------------------------------------------------------------------------------- /public/images/icons/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/edit.png -------------------------------------------------------------------------------- /public/images/icons/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/error.png -------------------------------------------------------------------------------- /public/images/icons/failed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/failed.png -------------------------------------------------------------------------------- /public/images/icons/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/help.png -------------------------------------------------------------------------------- /public/images/icons/inspect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/inspect.png -------------------------------------------------------------------------------- /public/images/icons/notice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/notice.png -------------------------------------------------------------------------------- /public/images/icons/pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/pending.png -------------------------------------------------------------------------------- /public/images/icons/popup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/popup.png -------------------------------------------------------------------------------- /public/images/icons/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/search.png -------------------------------------------------------------------------------- /public/images/icons/unchanged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/unchanged.png -------------------------------------------------------------------------------- /public/images/icons/unresponsive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/unresponsive.png -------------------------------------------------------------------------------- /public/images/icons/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/icons/warning.png -------------------------------------------------------------------------------- /public/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/loading.gif -------------------------------------------------------------------------------- /public/images/tipsy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sodabrew/puppet-dashboard/3974fbf3e904943a6880e7d0627f8b887f88b83e/public/images/tipsy.gif -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: / 3 | -------------------------------------------------------------------------------- /spec/controllers/application_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe ApplicationController, :type => :controller do 4 | before do 5 | class ApplicationController 6 | def generic_action 7 | @time_zone = Time.zone 8 | end 9 | end 10 | 11 | Rails.application.routes.draw do |map| 12 | get 'application/generic_action' 13 | end 14 | end 15 | 16 | after do 17 | Rails.application.reload_routes! 18 | end 19 | 20 | before :each do 21 | Time.zone = 'UTC' 22 | end 23 | 24 | it "should set the timezone to whatever is in SETTINGS.time_zone" do 25 | SETTINGS.stubs(:time_zone).returns('Pacific Time (US & Canada)') 26 | head :generic_action 27 | Time.zone.name.should == "Pacific Time (US & Canada)" 28 | end 29 | 30 | it "should raise if SETTINGS.time_zone is set to something invalid" do 31 | SETTINGS.stubs(:time_zone).returns('invalid') 32 | lambda { head :generic_action }.should raise_error StandardError, 'Invalid timezone "invalid"' 33 | Time.zone.name.should == "UTC" 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/controllers/delayed_job_failures_controller.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | require 'shared_behaviors/controller_mixins' 4 | 5 | describe DelayedJobFailuresController do 6 | def model; DelayedJobFailure end 7 | it_should_behave_like "without JSON pagination" 8 | 9 | it "should mark events read when asked" do 10 | event = DelayedJobFailure.create!(:summary => "foo").id 11 | DelayedJobFailure.find(event).read.should be_false 12 | post :index, :mark_all_read => nil 13 | DelayedJobFailure.find(event).read.should be_true 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/controllers/node_classes_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'shared_behaviors/controller_mixins' 3 | require 'shared_behaviors/sorted_index' 4 | 5 | describe NodeClassesController, :type => :controller do 6 | def model; NodeClass end 7 | 8 | it_should_behave_like "without JSON pagination" 9 | it_should_behave_like "with search by q and tag" 10 | it_should_behave_like "sorted index" 11 | 12 | end 13 | -------------------------------------------------------------------------------- /spec/controllers/pages_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe PagesController, :type => :controller do 4 | describe "#home" do 5 | before :each do 6 | SETTINGS.stubs(:no_longer_reporting_cutoff).returns(3600) 7 | 8 | [true, false].each do |hidden| 9 | prefix = hidden ? 'hidden:' : '' 10 | create(:node, :hidden => hidden, :name => prefix + 'unreported') 11 | [:unresponsive, :responsive, :failing, :pending, :changed, :unchanged].each do |node_status| 12 | create("#{node_status}_node".to_sym, :hidden => hidden, :name => prefix + node_status.to_s) 13 | end 14 | end 15 | end 16 | 17 | it "should properly categorize nodes" do 18 | get :home 19 | assigns[:all_nodes].map(&:name).should =~ %w[ unreported unresponsive responsive failing changed pending unchanged ] 20 | 21 | assigns[:unreported_nodes].map(&:name).should =~ %w[ unreported ] 22 | assigns[:unresponsive_nodes].map(&:name).should =~ %w[ unresponsive ] 23 | assigns[:failed_nodes].map(&:name).should =~ %w[ responsive failing ] 24 | assigns[:pending_nodes].map(&:name).should =~ %w[ pending ] 25 | assigns[:changed_nodes].map(&:name).should =~ %w[ changed ] 26 | assigns[:unchanged_nodes].map(&:name).should =~ %w[ unchanged ] 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/fixtures/reports/puppet26/report_error_missing_dependency.yaml: -------------------------------------------------------------------------------- 1 | --- !ruby/object:Puppet::Transaction::Report 2 | external_times: {} 3 | host: puppet.puppetlabs.vm 4 | logs: 5 | - !ruby/object:Puppet::Util::Log 6 | level: !ruby/sym info 7 | message: Caching catalog for puppet.puppetlabs.vm 8 | source: Puppet 9 | tags: 10 | - info 11 | time: 2010-07-22 12:16:05.073204 -07:00 12 | version: 2.6.0 13 | metrics: {} 14 | resource_statuses: {} 15 | time: 2010-07-22 12:16:04.059816 -07:00 -------------------------------------------------------------------------------- /spec/helpers/pages_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe PagesHelper, :type => :helper do 4 | 5 | #Delete this example and add some real ones or delete this file 6 | it "should be included in the object returned by #helper" do 7 | included_modules = (class << helper; self; end).send :included_modules 8 | included_modules.should include(PagesHelper) 9 | end 10 | 11 | describe '#percentage' do 12 | describe 'with appropriate values passed in' do 13 | it 'should report the ratio of those values' do 14 | helper.percentage(50,100).should == 50 15 | helper.percentage(40,100).should == 40 16 | helper.percentage(1,3).should == 33.3 17 | helper.percentage(1,0).should == 0 18 | end 19 | end 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /spec/helpers/status_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe StatusHelper, :type => :helper do 4 | 5 | #Delete this example and add some real ones or delete this file 6 | it "should be included in the object returned by #helper" do 7 | included_modules = (class << helper; self; end).send :included_modules 8 | included_modules.should include(StatusHelper) 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /spec/helpers/string_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe StringHelper, :type => :helper do 4 | describe ".is_md5?" do 5 | it "returns true for a valid md5" do 6 | helper.instance_eval{ is_md5?("abcdef0123456789abcdef0123456789") }.should == true 7 | end 8 | 9 | it "returns false for a value that is too short" do 10 | helper.instance_eval{ is_md5?("abcdef0123456789") }.should == false 11 | end 12 | 13 | it "returns false for a value that is too long" do 14 | helper.instance_eval{ is_md5?("abcdef012345678abcdef01234567899abcdef0123456789") }.should == false 15 | end 16 | 17 | it "returns false for a value that contains illegal characters" do 18 | helper.instance_eval{ is_md5?("this is not an md5") }.should == false 19 | end 20 | 21 | it "returns false for upper-case values" do 22 | helper.instance_eval{ is_md5?("ABCDEF0123456789ABCDEF0123456789") }.should == false 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/lib/core_callbacks_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'core' do 4 | before :each do 5 | @registry_hash = Registry.instance.instance_variable_get('@registry') 6 | end 7 | 8 | describe 'report_view_widgets' do 9 | describe '800_resource_statuses' do 10 | it "should move 'failed' resource_statuses to the start" do 11 | callback = @registry_hash[:core][:report_view_widgets]['800_resource_statuses'] 12 | report = Report.create_from_yaml(File.read(File.join(Rails.root, 'spec/fixtures/reports/puppet26/report_error_on_package_service_and_files.yaml'))) 13 | 14 | statuses = nil 15 | mock_renderer = stub('view_renderer') 16 | mock_renderer.expects(:render).with do |name, args| 17 | statuses = args[:statuses] 18 | end 19 | 20 | callback.call(mock_renderer, report) 21 | 22 | statuses.map(&:first).should == ['failed', 'unchanged'] 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/lib/settings_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "SETTINGS" do 4 | it "should allow you to set the datetime_format" do 5 | Time.zone = "UTC" 6 | SETTINGS.stubs(:datetime_format).returns('%d-%m-%Y') 7 | Time.utc("2010", "11", "12", 12, 15, 00).to_s.should == '12-11-2010' 8 | end 9 | 10 | it "should allow you to set the date_format" do 11 | Time.zone = "UTC" 12 | SETTINGS.stubs(:date_format).returns('%A %B %d, %Y') 13 | Time.utc("2010", "11", "12", 12, 15, 00).to_s(:date).should == 'Friday November 12, 2010' 14 | end 15 | end 16 | 17 | -------------------------------------------------------------------------------- /spec/models/node_class_membership_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe NodeClassMembership, :type => :model do 4 | it { should belong_to(:node) } 5 | it { should belong_to(:node_class) } 6 | end 7 | -------------------------------------------------------------------------------- /spec/models/node_group_class_membership_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe NodeGroupClassMembership, :type => :model do 4 | it { should belong_to(:node_class) } 5 | it { should belong_to(:node_group) } 6 | end 7 | -------------------------------------------------------------------------------- /spec/models/node_group_edge_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe NodeGroupEdge, :type => :model do 4 | it {should belong_to(:to)} 5 | it {should belong_to(:from)} 6 | end 7 | -------------------------------------------------------------------------------- /spec/models/node_group_membership_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe NodeGroupMembership, :type => :model do 4 | it { should belong_to(:node) } 5 | it { should belong_to(:node_group) } 6 | 7 | it "should only allow a single association between the same node and group" do 8 | node = create(:node) 9 | node_group = create(:node_group) 10 | membership = NodeGroupMembership.create(:node => node, :node_group => node_group) 11 | 12 | membership.should be_valid 13 | 14 | duplicate = NodeGroupMembership.create(:node => node, :node_group => node_group) 15 | duplicate.should_not be_valid 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/models/parameter_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Parameter, :type => :model do 4 | before { @parameter = create(:parameter) } 5 | 6 | it { should belong_to(:parameterable) } 7 | it { should validate_presence_of(:key) } 8 | 9 | it "serializes values" do 10 | @parameter.value = [1,2,3] 11 | @parameter.save 12 | Parameter.find(@parameter.id).value.should == [1,2,3] 13 | end 14 | 15 | it "strips whitespace from keys" do 16 | @parameter.key = "test " 17 | @parameter.save 18 | Parameter.find(@parameter.id).key.should == "test" 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/rcov.opts.example: -------------------------------------------------------------------------------- 1 | --exclude "spec/*,gems/*" 2 | --rails 3 | -------------------------------------------------------------------------------- /spec/shared_behaviors/action_integration_behavior.rb: -------------------------------------------------------------------------------- 1 | shared_examples_for "a successful action" do 2 | it 'should successfully render' do 3 | do_request 4 | response.should be_success 5 | end 6 | end 7 | 8 | shared_examples_for "an embeddable action" do 9 | it 'should successfully render' do 10 | do_request 11 | response.should be_success 12 | end 13 | 14 | it 'should not use a layout' do 15 | do_request 16 | response.layout.should be_nil 17 | end 18 | end 19 | 20 | shared_examples_for "a redirecting action" do 21 | it 'should redirect' do 22 | do_request 23 | response.should be_redirect 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/shared_behaviors/sorted_index.rb: -------------------------------------------------------------------------------- 1 | shared_examples_for "sorted index" do 2 | describe "when retrieving" do 3 | it "should be sorted by default" do 4 | model_sym = model.name.underscore.to_sym 5 | c = create(model_sym, :name => 'c') 6 | b = create(model_sym, :name => 'b') 7 | d = create(model_sym, :name => 'd') 8 | a = create(model_sym, :name => 'a') 9 | 10 | model.all.should == [a,b,c,d] 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/spec.opts.example: -------------------------------------------------------------------------------- 1 | --colour 2 | --format 3 | s 4 | --loadby 5 | mtime 6 | --reverse 7 | -------------------------------------------------------------------------------- /spec/support/describe_reports.rb: -------------------------------------------------------------------------------- 1 | module DescribeReports 2 | REPORTS_META = YAML.load_file(Rails.root.join('spec', 'fixtures', 'reports', 'meta.yml')).with_indifferent_access 3 | 4 | # runs a set of specs for each report fixture categorized in 5 | # spec/fixtures/reports/meta.yml. It will provide a let accessor called 6 | # `report' for the current report and an `info' accessor for the meta info 7 | # for that report that can be used in the subject. 8 | # 9 | # Example: 10 | # 11 | # describe_reports "#changed_resources?" do subject { report.changed_resources? } it { should 12 | # == info[:changed] > 0} end 13 | # 14 | def describe_reports(*args, &block) 15 | options = {} 16 | options = args.pop if Hash === args.last 17 | 18 | desc = "" 19 | meta = REPORTS_META 20 | 21 | if options[:version] 22 | desc = " Puppet #{options[:version]}" 23 | meta = REPORTS_META.select{|_, info| info[:version] == options[:version]} 24 | end 25 | 26 | describe *args do 27 | meta.each do |file, info| 28 | describe file + desc do 29 | let(:report) { report_from_yaml(file) } 30 | let(:info) { info } 31 | instance_eval &block 32 | end 33 | end 34 | end 35 | end 36 | 37 | end 38 | -------------------------------------------------------------------------------- /spec/support/factory_bot.rb: -------------------------------------------------------------------------------- 1 | require 'factory_bot' 2 | 3 | RSpec.configure do |config| 4 | config.include FactoryBot::Syntax::Methods 5 | end 6 | -------------------------------------------------------------------------------- /spec/support/from_response_body.rb: -------------------------------------------------------------------------------- 1 | # Return YAML data structure parsed from the current +request.body+. 2 | def yaml_from_response_body 3 | return YAML.load(response.body) 4 | end 5 | 6 | # Return JSON data structure parsed from the current +request.body+. 7 | def json_from_response_body 8 | return ActiveSupport::JSON.decode(response.body) 9 | end 10 | -------------------------------------------------------------------------------- /spec/support/report_support.rb: -------------------------------------------------------------------------------- 1 | module ReportSupport 2 | REPORT_TEMPLATE = Rails.root.join('spec', 'fixtures', 'sample_report.yml.erb') 3 | 4 | def report_yaml_with(options={}) 5 | template = File.read(REPORT_TEMPLATE) 6 | ERB.new(template).result(options.send(:binding)) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/support/response_codes.rb: -------------------------------------------------------------------------------- 1 | module ActionDispatch 2 | class Response 3 | Rack::Utils::SYMBOL_TO_STATUS_CODE.each do |symbol, code| 4 | define_method("#{symbol}?") { self.code == code.to_s } unless instance_methods.include?("#{symbol}?") 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/support/should_matchers.rb: -------------------------------------------------------------------------------- 1 | require 'shoulda/matchers' 2 | 3 | Shoulda::Matchers.configure do |config| 4 | config.integrate do |with| 5 | # Choose a test framework: 6 | with.test_framework :rspec 7 | 8 | # Or, choose the following (which implies all of the above): 9 | with.library :rails 10 | end 11 | end 12 | 13 | -------------------------------------------------------------------------------- /spec/views/node_classes/_actions.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/node_classes/_actions.html.haml", :type => :view do 4 | include NodeClassesHelper 5 | 6 | describe "successful render" do 7 | before { render } 8 | 9 | it { rendered.should have_tag('a', :with => { :href => new_node_class_path }) } 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/views/node_classes/edit.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/node_classes/edit.html.haml", :type => :view do 4 | include NodeClassesHelper 5 | 6 | describe "successful render" do 7 | before :each do 8 | @node_class = create(:node_class) 9 | render 10 | end 11 | 12 | it { rendered.should have_tag('form', :with => { :method => 'post', :action => node_class_path(@node_class.id) }) } 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/views/node_classes/index.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/node_classes/index.html.haml", :type => :view do 4 | include NodeClassesHelper 5 | 6 | describe "successful render" do 7 | before :each do 8 | view.stubs(:action_name => 'index') 9 | @node_classes = [ create(:node_class), create(:node_class) ].paginate 10 | render 11 | end 12 | 13 | it "has node class items" do 14 | rendered.should have_tag('.node_class', :count => @node_classes.size) 15 | rendered.should have_tag("#node_class_#{@node_classes.last.id}") 16 | end 17 | 18 | it { rendered.should have_tag('form.search') } 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/views/node_classes/new.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/node_classes/new.html.haml", :type => :view do 4 | include NodeClassesHelper 5 | 6 | describe "successful render" do 7 | before :each do 8 | assigns[:node_class] = @node_class = create(:node_class) 9 | render 10 | end 11 | 12 | it { rendered.should have_tag('form', :with => { :method => 'post', :action => node_class_path(@node_class) }) } 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/views/node_classes/show.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/node_classes/show.html.haml", :type => :view do 4 | include NodeClassesHelper 5 | 6 | describe "successful render" do 7 | before :each do 8 | assigns[:node_class] = @node_class = create(:node_class) 9 | render 10 | end 11 | 12 | it { rendered.should have_tag 'h2', :text => /Class:\n#{@node_class.name}/ } 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/views/node_groups/_actions.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/node_groups/_actions.html.haml", :type => :view do 4 | include NodesHelper 5 | 6 | describe "successful render" do 7 | before { render } 8 | 9 | it { rendered.should have_tag('a', :with => { :href => new_node_group_path }) } 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/views/node_groups/_search.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/node_groups/_search.html.haml", :type => :view do 4 | include NodeGroupsHelper 5 | 6 | describe "successful render" do 7 | before { render } 8 | 9 | it { rendered.should have_tag('form.search') } 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/views/node_groups/index.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/node_groups/index.html.haml", :type => :view do 4 | include NodeGroupsHelper 5 | 6 | describe "successful render" do 7 | before :each do 8 | view.stubs(:action_name => 'index') 9 | assigns[:node_groups] = @node_groups = [ create(:node_group), create(:node_group) ].paginate 10 | render 11 | end 12 | 13 | it { rendered.should have_tag('.node_group', :count => @node_groups.size) } 14 | it { rendered.should have_tag("#node_group_#{@node_groups.last.id}") } 15 | it { rendered.should have_tag('form.search') } 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/views/node_groups/new.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/node_groups/new.html.haml", :type => :view do 4 | include NodeGroupsHelper 5 | 6 | describe "successful render" do 7 | before :each do 8 | assigns[:node_group] = @node_group = build(:node_group) 9 | render 10 | end 11 | 12 | it { rendered.should have_tag('form[method=post]', :with => { :action => node_groups_path }) } 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/views/node_groups/show.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/node_groups/show.html.haml", :type => :view do 4 | include NodeGroupsHelper 5 | 6 | describe "successful render" do 7 | before :each do 8 | assigns[:node_group] = @node_group = create(:node_group) 9 | render 10 | end 11 | 12 | it { rendered.should have_tag 'h2', :text => /Group:\n#{@node_group.name}/ } 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/views/nodes/new.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/nodes/new.html.haml", :type => :view do 4 | include NodesHelper 5 | 6 | describe "successful render" do 7 | before :each do 8 | assigns[:node] = @node = build(:node) 9 | render 10 | end 11 | 12 | it { rendered.should have_tag('form[method=post]', :with => { :action => nodes_path }) } 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/views/nodes/show.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/nodes/show.html.haml", :type => :view do 4 | include NodesHelper 5 | 6 | describe "successful render" do 7 | before(:each) do 8 | @report = create(:report) 9 | assigns[:node] = @node = @report.node 10 | render :template => "/nodes/show" 11 | end 12 | 13 | it { rendered.should have_tag('h2', :text => /#{@node.name}/) } 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/views/pages/home.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe '/pages/home', :type => :view do 4 | before :each do 5 | @all_nodes = [create(:node)] 6 | @unreported_nodes = [] 7 | @unresponsive_nodes = [] 8 | @failed_nodes = [] 9 | @pending_nodes = [] 10 | @changed_nodes = [] 11 | @unchanged_nodes = [] 12 | 13 | render 14 | end 15 | 16 | it 'should have a correct delayed_job_failures link' do 17 | rendered.should have_tag('a', :href => '/delayed_job_failures', :text => 'Background Tasks') 18 | end 19 | 20 | it 'should have a correct radiator link' do 21 | rendered.should have_tag('a', :href => '/radiator', :text => 'Radiator View') 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/views/reports/_report.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/reports/_report.html.haml", :type => :view do 4 | include ReportsHelper 5 | 6 | describe "successful render" do 7 | before :each do 8 | assigns[:report] = @report = create(:report) 9 | view.stubs(:resource => @report) 10 | render 'reports/report', :report => @report 11 | end 12 | 13 | it { rendered.should have_tag('span.status', :text => /Report/) } 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/views/reports/_report_status_icon.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/reports/_report_status_icon.html.haml", :type => :view do 4 | include ReportsHelper 5 | 6 | describe "successful render" do 7 | before :each do 8 | assigns[:report] = @report = create(:report, :status => "changed") 9 | view.stubs(:resource => @report) 10 | render :partial => 'reports/report_status_icon', :locals => { :report => @report } 11 | end 12 | 13 | it { rendered.should have_tag('img', :with => { :src => '/images/icons/changed.png' }) } 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/views/reports/_report_status_td.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/reports/_report_status_td.html.haml", :type => :view do 4 | include ReportsHelper 5 | 6 | describe "successful render" do 7 | before :each do 8 | assigns[:report] = @report = create(:report, :status => "changed") 9 | render :partial => 'reports/report_status_td', :locals => { :report => @report } 10 | end 11 | 12 | it { rendered.should have_tag('td.status.changed img', :with => { :src => '/images/icons/changed.png' }) } 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/views/reports/index.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/reports/index.html.haml", :type => :view do 4 | describe "the response" do 5 | before :each do 6 | @nodes = [create(:node), create(:node)] 7 | assigns[:reports] = @reports = @nodes.map { |node| create(:report, :host => node.name) }.paginate 8 | render 9 | end 10 | 11 | it { rendered.should have_tag('.report', :count => @reports.size) } 12 | it { rendered.should have_tag("#report_#{@reports.first.id}") } 13 | end 14 | 15 | describe "the response with a report lacking metrics" do 16 | before :each do 17 | @report = create(:report) 18 | assigns[:reports] = @reports = [ @report ].paginate 19 | render 20 | end 21 | 22 | it { rendered.should have_tag('.report', :count => 1) } 23 | it { rendered.should have_tag("#report_#{@report.id}") } 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/views/reports/show.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/reports/show.html.haml", :type => :view do 4 | include ReportsHelper 5 | 6 | describe "successful render" do 7 | before :each do 8 | report_yaml = File.read(File.join(Rails.root, "spec/fixtures/reports/puppet26/report_ok_service_started_ok.yaml")) 9 | @report = Report.create_from_yaml(report_yaml) 10 | render 11 | end 12 | 13 | # 14 | # Changed 15 | it { rendered.should have_tag('.status img', :with => { :src => '/images/icons/changed.png' }) } 16 | it { rendered.should have_tag('a', :with => { :href => node_path(@report.node) }) } 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/views/statuses/_run_failure.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/statuses/_run_failure.html.haml", :type => :view do 4 | include ReportSupport 5 | 6 | describe "successful render" do 7 | specify do 8 | render 9 | rendered.should be_an_instance_of(String) 10 | end 11 | 12 | it "should display the specified number of days of data" do 13 | @node = Node.create!(:name => "node") 14 | 15 | 32.times do |n| 16 | report_yaml = report_yaml_with(:host => "node", :time => n.days.ago) 17 | Report.create_from_yaml(report_yaml) 18 | end 19 | 20 | SETTINGS.stubs(:daily_run_history_length).returns(20) 21 | 22 | render 23 | rendered.should have_tag("tr.labels th", :count => 20) 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/watchr.rb.example: -------------------------------------------------------------------------------- 1 | # SUMMARY: watchr provides a way to continuously run tests, it's an alternative to Autotest. 2 | # SETUP: 3 | # 1. Install the watchr library: 4 | # gem install watchr 5 | # 2. Make a copy of the `watchr.rb` script and customize to taste: 6 | # cp spec/watchr.rb{.example,} 7 | # USAGE: watchr spec/watchr.rb 8 | 9 | def run_spec_file(test_file) 10 | output_header test_file 11 | system %Q{./script/spec '#{test_file}' --diff unified --format nested --color} 12 | output_footer test_file 13 | end 14 | 15 | def output_header(test_file) 16 | puts "\n\n" 17 | system "date" 18 | puts test_file 19 | end 20 | 21 | def output_footer(test_file) 22 | system %Q{echo -ne \a} 23 | end 24 | 25 | watch('app/(.*)\.rb') do |md| 26 | test_file = "spec/#{md[1]}_spec.rb" 27 | 28 | run_spec_file test_file 29 | end 30 | 31 | watch('spec/.*_spec\.rb') do |md| 32 | test_file = "#{md[0]}" 33 | 34 | run_spec_file test_file 35 | end 36 | -------------------------------------------------------------------------------- /spool/.gitignore: -------------------------------------------------------------------------------- 1 | # This directory is used to spool YAML reports for background importing. 2 | # None of the content lives beyond the time to load the report. 3 | * 4 | -------------------------------------------------------------------------------- /tmp/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | --------------------------------------------------------------------------------