diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 02fb352..09c49ee 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -38,7 +38,7 @@ jobs:
- uses: carlosperate/download-file-action@v1.1.2
id: download-mdl-config
with:
- file-url: 'https://raw.githubusercontent.com/chef/chef-web-docs/main/.markdownlint.yaml'
+ file-url: 'https://raw.githubusercontent.com/chef/chef-client-docs/main/.markdownlint.yaml'
file-name: 'markdownlint.yaml'
- uses: DavidAnson/markdownlint-cli2-action@v5
with:
@@ -57,7 +57,7 @@ jobs:
- uses: actions/checkout@v3
- uses: errata-ai/vale-action@reviewdog
with:
- files: '["archetypes", "content", "layouts"]'
- vale_flags: "--config=tools/vale/.vale-github-action.ini"
+ files: '["content", "layouts"]'
+ vale_flags: "--config=.vale.ini --minAlertLevel=error"
filter_mode: diff_context
fail_on_error: true
diff --git a/.vale.ini b/.vale.ini
index d243889..e38aae5 100644
--- a/.vale.ini
+++ b/.vale.ini
@@ -16,3 +16,6 @@ BasedOnStyles = chef, Microsoft, vale, write-good
# Ignore SVG markup
TokenIgnores = (\*\*\{\w*\}\*\*), (Master License and Services Agreement)
+
+# Modify rule alert levels
+write-good.ThereIs = warning
diff --git a/config/_default/menu.toml b/config/_default/menu.toml
index 9a6ca75..69be5f2 100644
--- a/config/_default/menu.toml
+++ b/config/_default/menu.toml
@@ -60,35 +60,195 @@ title = "Install"
identifier = "install"
[[install]]
- title = "Migration tool"
- identifier = "install/migration_tool"
+ title = "Installer"
+ identifier = "install/installer"
parent = "install"
+ weight = 20
[[install]]
- title = "Native installer"
- identifier = "install/installer"
+ title = "Migration Tool"
+ identifier = "install/migration_tool"
parent = "install"
+ weight = 30
[[licensing]]
title = "Licensing"
identifier = "licensing"
-[[agentless]]
-title = "Agentless"
-identifier = "agentless"
-
-[[workstation]]
-title = "Chef Workstation"
-identifier = "workstation"
-
- [[workstation]]
- title = "Knife"
- identifier = "workstation/knife"
- parent = "workstation"
- weight = 100
-
- [[workstation]]
- title = "Test Kitchen Enterprise"
- identifier = "workstation/tke"
- parent = "workstation"
- weight = 200
+[[features]]
+title = "Features"
+identifier = "features"
+
+ [[features]]
+ title = "Agentless Mode"
+ identifier = "features/agentless"
+ parent = "features"
+
+ [[features]]
+ title = "Resources"
+ identifier = "features/agentless/resources"
+ parent = "features/agentless"
+ weight = 40
+
+ [[features]]
+ title = "Chef Solo"
+ identifier = "features/chef_solo"
+ parent = "features"
+
+ [[features]]
+ title = "Ohai"
+ identifier = "features/ohai"
+ parent = "features"
+
+[[integrations]]
+title = "Integrations"
+identifier = "integrations"
+
+ [[integrations]]
+ title = "Azure"
+ identifier = "integrations/azure"
+ parent = "integrations"
+
+ [[integrations]]
+ title = "Windows"
+ identifier = "integrations/windows"
+ parent = "integrations"
+
+[[policy]]
+title = "Policy"
+identifier = "policy"
+
+[[security]]
+title = "Security"
+identifier = "security"
+
+[[cookbooks]]
+title = "Cookbooks"
+identifier = "cookbooks"
+
+ [[cookbooks]]
+ title = "Attributes"
+ identifier = "cookbooks/attributes"
+ parent = "cookbooks"
+ weight = 30
+
+ [[cookbooks]]
+ title = "Recipes"
+ identifier = "cookbooks/recipes"
+ parent = "cookbooks"
+ weight = 70
+
+[[infra_language]]
+title = "Infra language"
+identifier = "infra_language"
+
+[[resources]]
+title = "Resources"
+identifier = "resources"
+
+ [[resources]]
+ title = "Bundled resources"
+ parent = "resources"
+ identifier = "resources/bundled"
+
+ [[resources]]
+ title = "Custom resources"
+ parent = "resources"
+ identifier = "resources/custom"
+
+[[extension_apis]]
+title = "Extension APIs"
+identifier = "extension_apis"
+
+ [[extension_apis]]
+ title = "Compliance DSL"
+ identifier = "extension_apis/inspec/dsl_inspec/ Compliance DSL"
+ parent = "extension_apis"
+ url = "https://docs.chef.io/inspec/latest/profiles/controls/"
+ weight = 20
+
+ [[extension_apis]]
+ title = "Handlers"
+ identifier = "extension_apis/handlers"
+ parent = "extension_apis"
+ weight = 20
+
+ [[extension_apis]]
+ title = "Custom handlers"
+ identifier = "extension_apis/handlers/handlers.md#custom-handlers Custom Handlers"
+ parent = "extension_apis/handlers"
+ url = "/features/handlers/#custom-handlers"
+ weight = 10
+
+ [[extension_apis]]
+ title = "Community handlers"
+ identifier = "extension_apis/handlers/plugin_community.md#handlers Community Handlers"
+ parent = "extension_apis/handlers"
+ url = "/extension_apis/community_plugins/#handlers"
+ weight = 30
+
+ [[extension_apis]]
+ title = "Ohai plugins"
+ identifier = "extension_apis/ohai_plugins"
+ parent = "extension_apis"
+ weight = 40
+
+[[reference]]
+title = "Reference"
+identifier = "reference"
+
+ [[reference]]
+ title = "chef-solo (executable)"
+ identifier = "reference/ctl_chef_solo.md chef-solo (executable)"
+ parent = "reference"
+ url = "/features/chef_solo/ctl_chef_solo/"
+ weight = 20
+
+ [[reference]]
+ title = "Handler DSL"
+ identifier = "reference/dsl_handler.md Handler Commands"
+ parent = "reference"
+ url = "/extension_apis/dsl_handler/"
+ weight = 40
+
+ [[reference]]
+ title = "ohai (executable)"
+ identifier = "reference/ctl_ohai.md ohai (executable)"
+ parent = "reference"
+ url = "/features/ohai/ctl_ohai/"
+ weight = 50
+
+ [[reference]]
+ title = "supermarket-ctl"
+ identifier = "supermarket/reference/ctl_supermarket.md supermarket-ctl"
+ parent = "reference"
+ url = "https://docs.chef.io/supermarket/ctl_supermarket/"
+ weight = 60
+
+ [[reference]]
+ title = "client.rb"
+ identifier = "reference/config_rb_client.md client.rb"
+ parent = "reference"
+ url = "/install/config_rb_client/"
+ weight = 70
+
+ [[reference]]
+ title = "metadata.rb"
+ identifier = "reference/config_rb_metadata.md metadata.rb"
+ parent = "reference"
+ url = "/cookbooks/config_rb_metadata/"
+ weight = 80
+
+ [[reference]]
+ title = "Policyfile.rb"
+ identifier = "reference/config_rb_policyfile.md Policyfile.rb"
+ parent = "reference"
+ url = "/policy/config_rb_policyfile/"
+ weight = 90
+
+ [[reference]]
+ title = "solo.rb"
+ identifier = "reference/config_rb_solo.md solo.rb"
+ parent = "reference"
+ url = "/install/config_rb_solo/"
+ weight = 100
\ No newline at end of file
diff --git a/config/_default/params.toml b/config/_default/params.toml
index 17a1a85..c0adf98 100644
--- a/config/_default/params.toml
+++ b/config/_default/params.toml
@@ -7,7 +7,22 @@
# Menus are defined in the /config/_default/menu.toml file
#######
-menuOrder = ["landing_page", "install", "licensing", "agentless", "workstation", "resources", "chef_gem_server", "cookbooks", "reference", "release_notes"]
+menuOrder = [
+ "overview",
+ "install",
+ "licensing",
+ "quickstart",
+ "features",
+ "policy",
+ "integrations",
+ "security",
+ "cookbooks",
+ "infra_language",
+ "resources",
+ "extension_apis",
+ "troubleshooting",
+ "reference"
+]
#######
# robots = The default robots config applied to each page in the robots meta tag.
@@ -26,6 +41,10 @@ robots = ''
#######
breadcrumbs = true
+[[breadcrumb_base]]
+breadcrumb = "Documentation"
+url = "https://docs.chef.io"
+
#######
#
# Settings for the link and image render hooks.
diff --git a/config/branch-deploy/params.toml b/config/branch-deploy/params.toml
index 71a82e2..8b13789 100644
--- a/config/branch-deploy/params.toml
+++ b/config/branch-deploy/params.toml
@@ -1,5 +1 @@
-breadcrumbs = true
-[[breadcrumb_base]]
-breadcrumb = "Docs"
-url = "https://docs.chef.io"
diff --git a/config/vocabularies/Chef/accept.txt b/config/vocabularies/Chef/accept.txt
new file mode 100644
index 0000000..427adc8
--- /dev/null
+++ b/config/vocabularies/Chef/accept.txt
@@ -0,0 +1,2 @@
+Chef Backend
+[B|b]ackend
diff --git a/content/_index.md b/content/_index.md
index 64ee005..1158130 100644
--- a/content/_index.md
+++ b/content/_index.md
@@ -1,5 +1,5 @@
+++
-title = "Chef Infra Client 19 RC3"
+title = "Chef Infra Client"
linkTitle = "Chef Infra Client"
[cascade]
@@ -7,49 +7,89 @@ linkTitle = "Chef Infra Client"
breadcrumbs = true
st_robots = ''
-[menu.landing_page]
-title = "Chef Infra Client"
+[menu.overview]
+ title = "Chef Infra Client"
+ identifier = "overview/Client Overview"
+ parent = "overview"
+ weight = 10
+++
-To provide enterprise stability, Progress Chef has created a [Long Term Support (LTS) model](https://www.chef.io/blog/long-term-support-progress-chef-providing-stability) for products.
-Chef Infra Client 19 is the first LTS version for infrastructure management and compliance mode.
-This release---Release Candidate 3 (RC3)---is a preview for a limited audience to provide candid feedback on Chef Infra Client,
-the new Infra Client migration tool, and updated Test Kitchen developer tools to ensure a seamless transition at the time of general availability (GA).
+Chef Infra Client is an agent that runs locally on every node that's under management by Chef Infra Server.
+Chef Infra Client transforms your infrastructure into code by automatically configuring systems to match your desired state.
+
+When Chef Infra Client runs, it performs all the steps required to bring a node into the expected state, including:
+
+- Registering and authenticating the node with Chef Infra Server
+- Synchronizing cookbooks from Chef Infra Server to the node
+- Compiling the resource collection by loading each of the required cookbooks, including recipes, attributes, and all other dependencies
+- Taking the appropriate and required actions to configure the node based on recipes and attributes
+- Reporting summary information on the run to Chef Automate
+
+## Chef Infra Client components
+
+Chef Infra Client works with key components to manage your infrastructure:
+
+### Compliance Phase
+
+The Compliance Phase is an integrated security and compliance feature that runs Chef InSpec profiles automatically as part of every Chef Infra Client run.
+This phase allows you to continuously audit your infrastructure for compliance with security policies and regulatory requirements without managing separate tools or processes.
+
+For detailed information, see [About the Compliance Phase](/features/chef_compliance_phase/).
+
+### Node
+
+A node represents any system that Chef Infra Client manages - whether it's a virtual machine, container instance, or physical server.
+Every node runs Chef Infra Client and maintains its configuration state according to the policies you define.
+
+### Cookbooks and recipes
+
+Cookbooks contain the instructions (recipes) that tell Chef Infra Client how to configure your systems.
+Recipes use resources to describe the desired state of system components like packages, files, and services.
+
+### Run list
+
+The run list defines which cookbooks and recipes Chef Infra Client should execute on a node and in what order.
+You can customize run lists for different node types or environments.
+
+### Ohai
+
+Ohai is a system profiling tool that collects detailed information about your nodes, including hardware details, network configuration, and operating system data.
+Chef Infra Client uses this information to make intelligent configuration decisions.
+
+### Agentless
-The new Chef Infra Client migration tool simplifies the transition from previous methods of installing and maintaining earlier versions of Infra Client to Chef Infra Client 19 release candidates and the final LTS version.
+Agentless allows you to execute Infra Client runs on a target node over SSH without having Chef Infra Client installed on the node.
-The new Test Kitchen Enterprise bundle is a fully Chef-maintained version of Test Kitchen that will be part of Chef Workstation at the time of release.
+For more details and setup instructions, see the [Agentless documentation](/features/agentless/).
-**Important:** Use Chef Infra Client 19 RC3 in non-production environments to verify existing deployment patterns and content against customer-specific infrastructure platforms.
+## How Chef Infra Client works
-## Supported environments
+Chef Infra Client operates on a pull-based model where nodes periodically contact Chef Infra Server to retrieve their configuration policies.
+This approach ensures that your infrastructure remains in the desired state even if individual nodes experience temporary disconnections or issues.
-Chef Infra Client RC3 supports testing in non-production environments on Linux and Windows x86-64 systems.
-Agentless Mode and Chef Workstation 26 RC3 are supported on Linux systems.
+## Common use cases
-This release allows you to:
+You can use Chef Infra Client to automate infrastructure management tasks:
-- Determine if the migration tool can upgrade your infrastructure to Chef Infra Client 19
-- Gain familiarity with Habitat-based builds
-- Prepare for new licensing requirements
+- **Server provisioning**: Automatically configure new servers with required software and settings
+- **Application deployment**: Deploy and configure applications across different environments
+- **Security compliance**: Enforce security policies and compliance requirements
+- **Configuration drift prevention**: Continuously check and correct configuration changes
+- **Environment management**: Maintain consistent configurations across development, staging, and production environments
-## Key features
+## The Chef Infra Client run
-Chef Infra Client 19 has the following key features:
+{{< readfile file="content/reusable/md/chef_client_run.md" >}}
-- **Long-term support (LTS):** Chef Infra Client 19 uses Habitat-based packaging instead of traditional omnibus builds.
-- **Test Kitchen Enterprise:** A foundational development tool for testing cookbooks and profiles across versions of Chef Infra Client.
- Chef InSpec receives full support from Chef in a modularized Chef Workstation toolkit.
-- **Standard licensing:** Infra Client 19 and Test Kitchen Enterprise use standard licensing for commercial, community, and trial customers.
-- **Enhanced performance:** Chef InSpec resource packs will be modularized to improve performance.
-- **Migration tool:** The Chef Infra Client migration tool installs and upgrades from previous versions to Chef Infra 19, supporting side-by-side installations.
+## Related content
-## Important changes
+- [Chef Infra Client (executable)](/reference/ctl_chef_client/)
+- [Chef Infra Server](https://docs.chef.io/server/)
+- [Cookbooks](/cookbooks/)
+- [Nodes](/overview/nodes/)
+- [Run Lists](/policy/run_lists/)
-Customers moving to Chef Infra Client 19 should be aware of these significant changes:
+## Next steps
-- **Platform support:** RC3 supports Linux and Windows x86-64 infrastructure. Future releases will expand support to include traditional Chef platforms.
-- **Packaging changes:** Chef no longer provides Omnibus builds for Infra Client and associated tools.
-- **New packaging options:** Chef now offers OS-native and Habitat-based packaging.
-- **Modular components:** Chef Workstation components become modularized to provide better support for individual tools.
-- **InSpec changes:** Chef InSpec resource packs become modularized for InSpec as part of the InSpec 7 LTS release (separate from the Infra Client LTS release).
+- [Install Chef Workstation](https://docs.chef.io/workstation/install_workstation/)
+- [Bootstrap Nodes](/install/install_bootstrap/)
diff --git a/content/agentless/resources/_index.md b/content/agentless/resources/_index.md
deleted file mode 100644
index 6aa2893..0000000
--- a/content/agentless/resources/_index.md
+++ /dev/null
@@ -1,106 +0,0 @@
-+++
-title = "Supported Chef Infra resources in Agentless Mode"
-linkTitle = "Resources"
-
-[menu.agentless]
-title = "Supported resources"
-identifier = "agentless/resources/overview"
-parent = "agentless"
-weight = 10
-+++
-
-The following Chef Infra resources are supported in Agentless Mode.
-
-| **Resources Name** | **Verified Platforms** | **Remarks** |
-|---|---|---|
-| [alternatives](https://docs.chef.io/resources/alternatives/) | Ubuntu, Linux | |
-| [apt_package](https://docs.chef.io/resources/apt_package/) | Ubuntu | |
-| [apt_preference](https://docs.chef.io/resources/apt_preference/) | Ubuntu, Linux | |
-| [apt_repository](https://docs.chef.io/resources/apt_repository/) | Ubuntu, Linux | |
-| [apt_update](https://docs.chef.io/resources/apt_update/) | Ubuntu, Linux | |
-| [bash](https://docs.chef.io/resources/bash/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
-| [breakpoint](https://docs.chef.io/resources/breakpoint/) | Ubuntu, Linux | |
-| [chef_acl](https://docs.chef.io/resources/chef_acl/) | Ubuntu, Linux, CentOS 9 | |
-| [chef_client](https://docs.chef.io/resources/chef_client/) | Ubuntu 24.04, Linux Red Hat 9, Solaris, Alpine, SUSE | |
-| [chef_client_config](https://docs.chef.io/resources/chef_client_config/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
-| [chef_container](https://docs.chef.io/resources/chef_container/) | Ubuntu, Linux | |
-| [chef_data_bag](https://docs.chef.io/resources/chef_data_bag/) | Ubuntu, Linux | |
-| [chef_environment](https://docs.chef.io/resources/chef_environment/) | Ubuntu, Linux | |
-| [chef_group](https://docs.chef.io/resources/chef_group/) | Ubuntu 24.04 and 18.04, RHEL | |
-| [chef_node](https://docs.chef.io/resources/chef_node/) | Ubuntu 24.04, Linux Red Hat 9 | |
-| [chef_organization](https://docs.chef.io/resources/chef_organization/) | Ubuntu 24.04 and 18.04, RHEL | |
-| [chef_role](https://docs.chef.io/resources/chef_role/) | Ubuntu 24.04, Linux Red Hat 9, Solaris, Alpine, SUSE | |
-| [chef_sleep](https://docs.chef.io/resources/chef_sleep/) | Ubuntu, Linux | |
-| [chef_user](https://docs.chef.io/resources/chef_user/) | Ubuntu 24.04 and 18.04, RHEL, Solaris, Alpine, SUSE | |
-| [cookbook_file](https://docs.chef.io/resources/cookbook_file/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
-| [cron](https://docs.chef.io/resources/cron/) | Ubuntu, Linux, Solaris SunOS, Alpine | |
-| [cron_access](https://docs.chef.io/resources/cron_access/) | Ubuntu, Linux, Solaris SunOS, Alpine | |
-| [cron_d](https://docs.chef.io/resources/cron_d/) | Ubuntu, Linux | |
-| [csh](https://docs.chef.io/resources/csh/) | Ubuntu 24.04, Linux Red Hat 9, Alpine | |
-| [directory](https://docs.chef.io/resources/directory/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
-| [execute](https://docs.chef.io/resources/execute/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
-| [file](https://docs.chef.io/resources/file/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
-| [freebsd_package](https://docs.chef.io/resources/freebsd_package/) | FreeBSD 14 | Only supported on FreeBSD. |
-| [git](https://docs.chef.io/resources/git/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
-| [group](https://docs.chef.io/resources/group/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
-| [habitat_config](https://docs.chef.io/resources/habitat_config/) | Ubuntu 24.04, Linux Red Hat 9, Solaris, Alpine, SUSE | |
-| [habitat_install](https://docs.chef.io/resources/habitat_install/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
-| [habitat_package](https://docs.chef.io/resources/habitat_package/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
-| [habitat_service](https://docs.chef.io/resources/habitat_service/) | Ubuntu, Linux | |
-| [habitat_sup](https://docs.chef.io/resources/habitat_sup/) | Ubuntu, Linux | |
-| [hostname](https://docs.chef.io/resources/hostname/) | Ubuntu, Linux | |
-| [http_request](https://docs.chef.io/resources/http_request/) | Ubuntu, Linux, , Solaris, Alpine, SUSE | |
-| [ifconfig](https://docs.chef.io/resources/ifconfig/) | Ubuntu, Linux | |
-| [inspec_input](https://docs.chef.io/resources/inspec_input/) | Ubuntu 24.04, Linux Red Hat 9 | |
-| [inspec_waiver](https://docs.chef.io/resources/inspec_waiver/) | Ubuntu, Linux | |
-| [inspec_waiver_file_entry](https://docs.chef.io/resources/inspec_waiver_file_entry/) | Ubuntu, Linux | |
-| [kernel_module](https://docs.chef.io/resources/kernel_module/) | Ubuntu, Linux | |
-| [ksh](https://docs.chef.io/resources/ksh/) | Ubuntu 24.04, Linux Red Hat 9, Solaris, Alpine, SUSE | |
-| [link](https://docs.chef.io/resources/link/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
-| [locale](https://docs.chef.io/resources/locale/) | Ubuntu | |
-| [log](https://docs.chef.io/resources/log/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
-| [mount](https://docs.chef.io/resources/mount/) | Ubuntu 24.04, CentOS 9 | |
-| [notify_group](https://docs.chef.io/resources/notify_group/) | Ubuntu, Linux | |
-| [ohai](https://docs.chef.io/resources/ohai/) | Ubuntu, Linux | |
-| [ohai_hint](https://docs.chef.io/resources/ohai_hint/) | Ubuntu, Linux | |
-| [owner](https://docs.chef.io/resources/owner/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
-| [package](https://docs.chef.io/resources/package/) | Ubuntu, Linux, CentOS 9, Solaris, Alpine, SUSE | |
-| [perl](https://docs.chef.io/resources/perl/) | Ubuntu | |
-| [python](https://docs.chef.io/resources/python/) | Ubuntu 24.04, Linux Red Hat 9, Solaris, Alpine, SUSE | |
-| [reboot](https://docs.chef.io/resources/reboot/) | Ubuntu, Linux | |
-| [remote_file](https://docs.chef.io/resources/remote_file/) | Ubuntu, Linux, CentOS 9, Solaris, Alpine, SUSE | |
-| [rhsm_errata](https://docs.chef.io/resources/rhsm_errata/) | Linux (redhat) | |
-| [rhsm_errata_level](https://docs.chef.io/resources/rhsm_errata_level/) | Linux (redhat) | |
-| [rhsm_register](https://docs.chef.io/resources/rhsm_register/) | Linux (redhat) | |
-| [rhsm_repo](https://docs.chef.io/resources/rhsm_repo/) | Linux (redhat) | |
-| [rhsm_subscription](https://docs.chef.io/resources/rhsm_subscription/) | Linux (redhat) | |
-| [route](https://docs.chef.io/resources/route/) | Ubuntu 24.04 / CentOS 9 | |
-| [rpm_package](https://docs.chef.io/resources/rpm_package/) | CentOS 9 | The RPM package must be locally available on the remote system. |
-| [ruby_block](https://docs.chef.io/resources/ruby_block/) | Ubuntu, Linux, CentOS 9 | |
-| [script](https://docs.chef.io/resources/script/) | Ubuntu 24.04, Linux Red Hat 9, , Solaris, Alpine | |
-| [selinux_boolean](https://docs.chef.io/resources/selinux_boolean/) | Ubuntu, Linux | |
-| [selinux_fcontext](https://docs.chef.io/resources/selinux_fcontext/) | Ubuntu, Linux | |
-| [selinux_install](https://docs.chef.io/resources/selinux_install/) | Ubuntu, Linux | |
-| [selinux_login](https://docs.chef.io/resources/selinux_login/) | Ubuntu, Linux | |
-| [selinux_module](https://docs.chef.io/resources/selinux_module/) | Ubuntu, Linux | |
-| [selinux_permissive](https://docs.chef.io/resources/selinux_permissive/) | Ubuntu, Linux | |
-| [selinux_port](https://docs.chef.io/resources/selinux_port/) | Ubuntu, Linux | |
-| [selinux_state](https://docs.chef.io/resources/selinux_state/) | Ubuntu, Linux | |
-| [selinux_user](https://docs.chef.io/resources/selinux_user/) | Ubuntu, Linux | |
-| [service](https://docs.chef.io/resources/service/) | Ubuntu, Linux, CentOS 9, Solaris, Alpine, SUSE | `crond` for Linux |
-| [snap_package](https://docs.chef.io/resources/snap_package/) | Ubuntu 24.04 | Only supported on Linux. |
-| [ssh_known_hosts_entry](https://docs.chef.io/resources/ssh_known_hosts_entry/) | Ubuntu, Linux | |
-| [subversion](https://docs.chef.io/resources/subversion/) | Ubuntu 24.04, Linux Red Hat 9, CentOS 9 | The subversion resource has known bugs and may not work as expected. For more information, see the Chef GitHub issues, particularly [#4050](https://github.com/chef/chef/issues/4050) and [#4257](https://github.com/chef/chef/issues/4257). |
-| [sudo](https://docs.chef.io/resources/sudo/) | Ubuntu, Linux, CentOS 9, Solaris, Alpine, SUSE | |
-| [swap_file](https://docs.chef.io/resources/swap_file/) | Ubuntu, Linux | |
-| [sysctl](https://docs.chef.io/resources/sysctl/) | Ubuntu, Linux | |
-| [systemd_unit](https://docs.chef.io/resources/systemd_unit/) | Ubuntu, Linux | |
-| [template](https://docs.chef.io/resources/template/) | Ubuntu, Linux, CentOS 9, Solaris, Alpine, SUSE | Require absolute path for source attribute. |
-| [timezone](https://docs.chef.io/resources/timezone/) | Linux, Solaris, Alpine, SUSE | |
-| [user](https://docs.chef.io/resources/user/) | Ubuntu, Linux | |
-| [user_ulimit](https://docs.chef.io/resources/user_ulimit/) | Ubuntu, Linux | |
-| [yum_package](https://docs.chef.io/resources/yum_package/) | CentOS 9 | Only supported on Linux. |
-| [yum_repository](https://docs.chef.io/resources/yum_repository/) | Linux | |
-| [yum_repository](https://docs.chef.io/resources/yum_repository/) | CentOS 9, RHEL 8 | Only supported on Linux. |
-| [zypper_package](https://docs.chef.io/resources/zypper_package/) | SUSE Linux 15 | |
-| [solaris_package](https://docs.chef.io/resources/solaris_package/) | Solaris | |
diff --git a/content/cookbooks.md b/content/cookbooks.md
deleted file mode 100644
index 59c5262..0000000
--- a/content/cookbooks.md
+++ /dev/null
@@ -1,8 +0,0 @@
-+++
-title = "Sample cookbook"
-
-[menu.cookbooks]
-title = "Sample cookbook"
-+++
-
-You can test Chef Infra Client 19 RC3 using a basic cookbook in the [infra-19-rc1-examples](https://github.com/chef/infra-19-rc1-examples/) repository. This includes a recipe that allows you to test Agentless Mode.
diff --git a/content/cookbooks/_index.md b/content/cookbooks/_index.md
new file mode 100644
index 0000000..a356426
--- /dev/null
+++ b/content/cookbooks/_index.md
@@ -0,0 +1,102 @@
++++
+title = "About Cookbooks"
+draft = false
+
+[menu]
+ [menu.cookbooks]
+ title = "About Cookbooks"
+ identifier = "cookbooks/cookbooks.md About Cookbooks"
+ parent = "cookbooks"
+ weight = 10
++++
+
+{{< readfile file="content/reusable/md/cookbooks_summary.md" >}}
+
+{{< readfile file="content/reusable/md/infra_lang_ruby.md" >}}
+
+{{< readfile file="content/reusable/md/infra_lang_summary.md" >}}
+
+Chef Infra Client runs a recipe only when instructed. When Chef Infra Client runs the same recipe more than once, the results will be the same system state each time. When a recipe is run against a system, but nothing has changed on either the system or in the recipe, Chef Infra Client won't change anything.
+
+## Components
+
+A cookbook is comprised of recipes and other optional components as files or directories.
+
+[Recipes](recipes)
+: Directory: `recipes/`
+
+ {{< readfile file="content/reusable/md/cookbooks_recipe.md" >}}
+
+[Attributes](attributes)
+: Directory: `attributes/`
+
+ {{< readfile file="content/reusable/md/cookbooks_attribute.md" >}}
+
+[Files](files)
+: Directory: `files/`
+
+ A file distribution is a specific type of resource that tells a cookbook how to distribute files, including by node, by platform, or by file version.
+
+[Libraries](libraries)
+: Directory: `libraries/`
+
+ A library allows the use of arbitrary Ruby code in a cookbook, either as a way to extend the Chef Infra Client language or to implement a new class.
+
+[Custom Resources](/resources/custom/)
+: Directory: `resources/`
+
+ A custom resource is an abstract approach for defining a set of actions and (for each action) a set of properties and validation parameters.
+
+[Templates](templates)
+: Directory: `templates/`
+
+ A template is a file written in markup language that uses Ruby statements to solve complex configuration scenarios.
+
+[Ohai Plugins](/extension_apis/custom_plugins/)
+: Directory: `ohai/`
+
+ Custom Ohai plugins can be written to load additional information about your nodes to be used in recipes. This requires Chef Infra Server 12.18.14 or later.
+
+[Metadata](config_rb_metadata)
+: File: `metadata.rb`
+
+ This file contains information about the cookbook such as the cookbook name, description, and version.
+
+## Community Cookbooks
+
+Chef maintains a large collection of cookbooks. In addition, there are thousands of cookbooks created and maintained by the community:
+
+| Components | Description |
+|:------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------:|
+| [Cookbooks Maintained by Chef](https://github.com/chef-cookbooks) | Chef maintains a collection of cookbooks that are widely used by the community. |
+| [Cookbooks Maintained by Sous Chefs](https://github.com/sous-chefs) | Sous Chefs is a community organization that collaborates to maintain many of the most used Chef cookbooks. |
+| [Cookbooks Maintained by the Community](https://supermarket.chef.io/cookbooks) | The community has authored thousands of cookbooks, ranging from niche cookbooks that are used by only a few organizations to popular cookbooks used by almost everyone. |
+
+## Generate a Cookbook
+
+Use the [chef generate cookbook subcommand](https://docs.chef.io/workstation/ctl_chef/#chef-generate-cookbook) to generate a cookbook.
+
+A cookbook generated with`chef generate cookbook custom_web` creates a cookbook named `custom_web` with the directory structure:
+
+```text
+. cookbooks
+└── custom_web
+ ├── CHANGELOG.md
+ ├── LICENSE
+ ├── Policyfile.rb
+ ├── README.md
+ ├── chefignore
+ ├── compliance
+ │ ├── README.md
+ │ ├── inputs
+ │ ├── profiles
+ │ └── waivers
+ ├── kitchen.yml
+ ├── metadata.rb
+ ├── recipes
+ │ └── default.rb
+ └── test
+ └── integration
+ └── default
+ └── default_test.rb
+```
diff --git a/content/cookbooks/attributes/_index.md b/content/cookbooks/attributes/_index.md
new file mode 100644
index 0000000..8e99e2c
--- /dev/null
+++ b/content/cookbooks/attributes/_index.md
@@ -0,0 +1,13 @@
++++
+title = "About Attributes"
+draft = false
+
+[menu]
+ [menu.cookbooks]
+ title = "Attributes"
+ identifier = "cookbooks/attributes/attributes.md Attributes"
+ parent = "cookbooks/attributes"
+ weight = 10
++++
+
+{{< readfile file="content/reusable/md/node_attribute.md" >}}
diff --git a/content/cookbooks/attributes/attribute_arrays.md b/content/cookbooks/attributes/attribute_arrays.md
new file mode 100644
index 0000000..6b404af
--- /dev/null
+++ b/content/cookbooks/attributes/attribute_arrays.md
@@ -0,0 +1,210 @@
++++
+title = "Attribute Arrays"
+description = "Define multiple attributes in an array or hash and deep merge"
+draft = false
+
+[menu]
+ [menu.cookbooks]
+ title = "Attributes Arrays"
+ identifier = "cookbooks/attributes/attribute_arrays Attribute Arrays"
+ parent = "cookbooks/attributes"
++++
+
+
+
+Attributes are typically defined in cookbooks, recipes, roles, and environments.
+These attributes are rolled up to the node level during a Chef Infra Client run.
+A recipe can store attribute values using a multi-level hash or array.
+
+For example, a group of attributes for web servers might be:
+
+```ruby
+override_attributes(
+ :apache => {
+ :listen_ports => [ 80 ],
+ :prefork => {
+ :startservers => 20,
+ :minspareservers => 20,
+ :maxspareservers => 40
+ }
+ }
+)
+```
+
+But, what if all of the web servers aren't the same or require a single attribute to have a different value?
+You could store these settings in two locations: one like the preceding example and one like the following:
+
+```ruby
+override_attributes(
+ :apache => {
+ :listen_ports => [ 80 ],
+ :prefork => {
+ :startservers => 30,
+ :minspareservers => 20,
+ :maxspareservers => 40
+ }
+ }
+)
+```
+
+But that isn't efficient, especially because most of them are identical.
+
+Chef Infra Client's deep merge capabilities allow you to layer attributes across cookbooks, recipes, roles, and environments.
+This allows an attribute to be reused across nodes, making use of default attributes set at the cookbook level, while also providing a way for certain attributes (with a higher attribute precedence) to be applied only when they're needed.
+
+For example, you can have a role named `baseline.rb`:
+
+```ruby
+name "baseline"
+description "The most basic role for all configurations"
+run_list "recipe[baseline]"
+
+override_attributes(
+ :apache => {
+ :listen_ports => [ 80 ],
+ :prefork => {
+ :startservers => 20,
+ :minspareservers => 20,
+ :maxspareservers => 40
+ }
+ }
+)
+```
+
+and a role named `web.rb`:
+
+```ruby
+name 'web'
+description 'Web server config'
+run_list 'role[baseline]'
+
+override_attributes(
+ :apache => {
+ :prefork => {
+ :startservers => 30
+ }
+ }
+)
+```
+
+The `web.rb` role references the `baseline.rb` role.
+The `web.rb` file only provides a value for one attribute: `:startservers`.
+When Chef Infra Client compares these attributes, the deep merge feature ensures that `:startservers` (and its value of `30`) is applied to any node for which the `web.rb` attribute structure should be applied.
+
+This approach allows a recipe like this:
+
+```ruby
+include_recipe 'apache2'
+Chef::Log.info(node['apache']['prefork'].to_hash)
+```
+
+and a `run_list` like this:
+
+```ruby
+run_list/web.json
+{
+ "run_list": [ "role[web]" ]
+}
+```
+
+to produce results like this:
+
+```ruby
+[Tue, 16 Aug 2011 14:44:26 -0700] INFO:
+ {
+ "startservers"=>30,
+ "minspareservers"=>20,
+ "maxspareservers"=>40,
+ "serverlimit"=>400,
+ "maxclients"=>400,
+ "maxrequestsperchild"=>10000
+ }
+```
+
+Even though the `web.rb` file doesn't contain attributes and values for `minspareservers`, `maxspareservers`, `serverlimit`, `maxclients`, and `maxrequestsperchild`, the deep merge capabilities pulled them in.
+
+## Attribute array logic
+
+The following sections show how the logic works for using deep merge to perform substitutions and additions of attributes.
+
+When an attribute value is a hash, that data is merged.
+When an attribute value is an array, if the attribute precedence levels are the same, then that data is merged.
+If the attribute value precedence levels in an array are different, then that data is replaced.
+For all other value types (such as strings or integers), that data is replaced.
+
+### Substitution
+
+The following examples show how the logic works for substituting an existing string using a hash:
+
+```text
+role_or_environment 1 { :x => '1', :y => '2' }
++
+role_or_environment 2 { :y => '3' }
+=
+{ :x => '1', :y => '3' }
+```
+
+For substituting an existing boolean using a hash:
+
+```text
+role_or_environment 1 { :x => true, :y => false }
++
+role_or_environment 2 { :y => true }
+=
+{ :x => true, :y => true }
+```
+
+For substituting an array with a hash:
+
+```text
+role_or_environment 1 [ '1', '2', '3' ]
++
+role_or_environment 2 { :x => '1' , :y => '2' }
+=
+{ :x => '1', :y => '2' }
+```
+
+When items can't be merged through substitution, the original data is overwritten.
+
+### Addition
+
+The following examples show how the logic works for adding a string
+using a hash:
+
+```text
+role_or_environment 1 { :x => '1', :y => '2' }
++
+role_or_environment 2 { :z => '3' }
+=
+{ :x => '1', :y => '2', :z => '3' }
+```
+
+For adding a string using an array:
+
+```text
+role_or_environment 1 [ '1', '2' ]
++
+role_or_environment 2 [ '3' ]
+=
+[ '1', '2', '3' ]
+```
+
+For adding a string using a multi-level hash:
+
+```text
+role_or_environment 1 { :x => { :y => '2' } }
++
+role_or_environment 2 { :x => { :z => '3' } }
+=
+{ :x => { :y => '2', :z => '3' } }
+```
+
+For adding a string using a multi-level array:
+
+```text
+role_or_environment 1 [ [ 1, 2 ] ]
++
+role_or_environment 2 [ [ 3 ] ]
+=
+[ [ 1, 2 ], [ 3 ] ]
+```
diff --git a/content/cookbooks/attributes/attribute_persistence.md b/content/cookbooks/attributes/attribute_persistence.md
new file mode 100644
index 0000000..8873178
--- /dev/null
+++ b/content/cookbooks/attributes/attribute_persistence.md
@@ -0,0 +1,114 @@
++++
+title = "Attribute Persistence"
+draft = false
+
+[menu]
+ [menu.cookbooks]
+ title = "Attribute Persistence"
+ identifier = "cookbooks/attributes/attribute_persistence.md Attributes"
+ parent = "cookbooks/attributes"
++++
+
+All attributes, except for normal attributes, are reset at the beginning of a Chef Infra Client run.
+Attributes set using `chef-client -j` with a JSON file have normal precedence and are persisted between Chef Infra Client runs.
+Chef Infra Client rebuilds these attributes using automatic attributes collected by Ohai at the beginning of each Chef Infra Client
+run, and then uses default and override attributes that are specified in cookbooks, roles, environments, and Policyfiles.
+All attributes are then merged and applied to the node according to attribute precedence.
+The attributes that were applied to the node are saved to Chef Infra Server as part of the node object at the conclusion of each Chef Infra Client run.
+
+## Limiting Attribute Persistence
+
+Some organizations find it helpful to control attribute data stored by Chef Infra Server, whether to limit the disk and CPU resources used when processing unused attributes, or to keep secrets like API keys from being submitted to the server.
+For example, your organization may find the data from the Ohai `Package` plugin useful when writing cookbooks, but don't see the need in saving ~100kB of package information for each Chef Infra Client run.
+Attribute data will still be available on the node within cookbooks, but any information you limit won't be saved to Chef Infra Server for use in searches.
+
+You can block or allow the saving of specific key using the [`client.rb`](/install/config_rb_client/) file.
+Each setting is an array of keys specifying each attribute to be filtered out or allowed. Use a "/" to separate subkeys, for example `network/interfaces`.
+
+For attributes containing slashes (`/`) within the attribute value, such as the `filesystem` attribute, use a nested array. For example:
+
+```ruby
+blocked_automatic_attributes [['filesystem', '/dev/diskos2']]
+```
+
+{{< note >}}
+
+In **Chef Infra Client 16.3**, the node Blacklist and Whitelist features were deprecated and renamed to Blocklist and Allowlist.
+In **Chef Infra Client 18.4.12** these features became EOL.
+For backwards compatibility, the old configuration values will continue to work through Chef Infra Client 17.x
+
+See each section below for the appropriate legacy configuration values if you are running legacy clients in your organization.
+
+Legacy attribute config mapping:
+
+- automatic_attribute_blacklist -> blocked_automatic_attributes
+- default_attribute_blacklist -> blocked_default_attributes
+- normal_attribute_blacklist -> blocked_normal_attributes
+- override_attribute_blacklist -> blocked_override_attributes
+- automatic_attribute_whitelist -> allowed_automatic_attributes
+- default_attribute_whitelist -> allowed_default_attributes
+- normal_attribute_whitelist -> allowed_normal_attributes
+- override_attribute_whitelist -> allowed_override_attributes
+
+{{< /note >}}
+
+### Attribute Blocklist
+
+{{< warning >}}
+
+{{< readfile file="content/reusable/md/node_attribute_blocklist_warning.md" >}}
+
+{{< /warning >}}
+
+{{< readfile file="content/reusable/md/node_attribute_blocklist.md" >}}
+
+### Attribute Allowlist
+
+{{< warning >}}
+
+{{< readfile file="content/reusable/md/node_attribute_allowlist_warning.md" >}}
+
+{{< /warning >}}
+
+Attributes are allowlisted by attribute type, with each attribute type being allowlisted independently in the `client.rb` file.
+
+The four attribute types are:
+
+- `automatic`
+- `default`
+- `normal`
+- `override`
+
+The allowlist settings are:
+
+`allowed_automatic_attributes`
+
+: An array that allows saving specific `automatic` attributes. For example: `['network/interfaces/eth0']`.
+
+ Default value: `nil`, all attributes are saved.
+
+ If the array is empty, no attributes are saved.
+
+`allowed_default_attributes`
+
+: An array that allows saving specific `default` attributes. For example: `['filesystem/dev/disk0s2/size']`.
+
+ Default value: `nil`, all attributes are saved.
+
+ If the array is empty, no attributes are saved.
+
+`allowed_normal_attributes`
+
+: An array that allows saving specific `normal` attributes. For example: `['filesystem/dev/disk0s2/size']`.
+
+ Default value: `nil`, all attributes are saved.
+
+ If the array is empty, no attributes are saved.
+
+`allowed_override_attributes`
+
+: An array that allows specific `override` attributes, preventing blocklisted attributes from being saved. For example: `['map - autohome/size']`.
+
+ Default value: `nil`, all attributes are saved.
+
+ If the array is empty, no attributes are saved.
diff --git a/content/cookbooks/attributes/attribute_precedence.md b/content/cookbooks/attributes/attribute_precedence.md
new file mode 100644
index 0000000..efb7acc
--- /dev/null
+++ b/content/cookbooks/attributes/attribute_precedence.md
@@ -0,0 +1,516 @@
++++
+title = "Attribute Precedence"
+draft = false
+
+[menu]
+ [menu.cookbooks]
+ title = "Attribute Precedence"
+ identifier = "cookbooks/attributes/attribute_precedence"
+ parent = "cookbooks/attributes"
++++
+
+Chef Infra Client applies attributes in the following
+order:
+
+| Application Order (Last One Wins) | Attribute Type | Source Order |
+|-----------------------------------|------------------|---------------------------------------------------------------------|
+| 1 | `default` | Cookbook attribute fileRecipeEnvironmentRole |
+| 2 | `force_default` | Cookbook attribute fileRecipe |
+| 3 | `normal` | JSON file passed with `chef-client -j`Cookbook attribute fileRecipe |
+| 4 | `override` | Cookbook attribute fileRecipeRoleEnvironment |
+| 5 | `force_override` | Cookbook attribute fileRecipe |
+| 6 | `automatic` | Identified by Ohai at the start of a Chef Infra Client Run |
+
+{{< note >}}
+
+The attribute precedence order for the sources "roles" and "environments" are opposite in the `default` and `override`. The `default` order is **environment** then **role**. The `override` order is **role** then **environment**
+
+Applying the role `override` first lets you use the same role in a set of environments.
+Applying the environment `override` on top of the role `override` lets you define a subset of these with environment-specific settings.
+
+This is useful if you have an environment that's different within a sub-set of a role. For example, the role for an application server may exist in all environments, but one environment may use a different database server.
+
+{{< /note >}}
+
+Attribute precedence, viewed from the same perspective as the overview
+diagram, where the numbers in the diagram match the order of attribute
+precedence:
+
+
+
+Attribute precedence, when viewed as a table:
+
+| | Attribute Files | Node/Recipe | Environment | Role | Ohai Data |
+|----------------|-----------------|-------------|-------------|------|-----------|
+| default | 1 | 2 | 3 | 4 | |
+| force_default | 5 | 6 | | | |
+| normal | 7 | 8 | | | |
+| override | 9 | 10 | 12 | 11 | |
+| force_override | 13 | 14 | | | |
+| automatic | | | | | 15 |
+
+## Examples
+
+The following examples are listed from low to high precedence.
+
+**Default attribute in /attributes/default.rb**
+
+```ruby
+default['apache']['dir'] = '/etc/apache2'
+```
+
+**Default attribute in node object in recipe**
+
+```ruby
+node.default['apache']['dir'] = '/etc/apache2'
+```
+
+**Default attribute in /environments/environment_name.rb**
+
+```ruby
+default_attributes({ 'apache' => {'dir' => '/etc/apache2'}})
+```
+
+**Default attribute in /roles/role_name.rb**
+
+```ruby
+default_attributes({ 'apache' => {'dir' => '/etc/apache2'}})
+```
+
+**Normal attribute set as a cookbook attribute**
+
+```ruby
+normal['apache']['dir'] = '/etc/apache2'
+```
+
+**Normal attribute set in a recipe**
+
+```ruby
+node.normal['apache']['dir'] = '/etc/apache2'
+```
+
+**Override attribute in /attributes/default.rb**
+
+```ruby
+override['apache']['dir'] = '/etc/apache2'
+```
+
+**Override attribute in /roles/role_name.rb**
+
+```ruby
+override_attributes({ 'apache' => {'dir' => '/etc/apache2'}})
+```
+
+**Override attribute in /environments/environment_name.rb**
+
+```ruby
+override_attributes({ 'apache' => {'dir' => '/etc/apache2'}})
+```
+
+**Override attribute in a node object (from a recipe)**
+
+```ruby
+node.override['apache']['dir'] = '/etc/apache2'
+```
+
+**Ensure that a default attribute has precedence over other attributes**
+
+When a default attribute is set like this:
+
+```ruby
+default['attribute'] = 'value'
+```
+
+any value set by a role or an environment will replace it. To prevent
+this value from being replaced, use the `force_default` attribute
+precedence:
+
+```ruby
+force_default['attribute'] = 'I will crush you, role or environment attribute'
+```
+
+or:
+
+```ruby
+default!['attribute'] = "The '!' means I win!"
+```
+
+**Ensure that an override attribute has precedence over other
+attributes**
+
+When an override attribute is set like this:
+
+```ruby
+override['attribute'] = 'value'
+```
+
+any value set by a role or an environment will replace it. To prevent
+this value from being replaced, use the `force_override` attribute
+precedence:
+
+```ruby
+force_override['attribute'] = 'I will crush you, role or environment attribute'
+```
+
+or:
+
+```ruby
+override!['attribute'] = "The '!' means I win!"
+```
+
+## Change Attributes
+
+Attribute precedence levels may be:
+
+- Removed for a specific, named attribute precedence level.
+- Removed for all attribute precedence levels.
+- Fully assigned attributes.
+
+### Remove Precedence Level
+
+A specific attribute precedence level for default, normal, and override
+attributes may be removed by using one of the following syntax patterns.
+
+For default attributes:
+
+- `node.rm_default('foo', 'bar')`
+
+For normal attributes:
+
+- `node.rm_normal('foo', 'bar')`
+
+For override attributes:
+
+- `node.rm_override('foo', 'bar')`
+
+These patterns return the computed value of the key being deleted for
+the specified precedence level.
+
+#### Examples
+
+The following examples show how to remove a specific, named attribute
+precedence level.
+
+**Delete a default value when only default values exist**
+
+Given the following code structure under `'foo'`:
+
+```ruby
+node.default['foo'] = {
+ 'bar' => {
+ 'baz' => 52,
+ 'thing' => 'stuff',
+ },
+ 'bat' => {
+ 'things' => [5, 6],
+ },
+}
+```
+
+And some role attributes:
+
+```ruby
+# Please don't ever do this in real code :)
+node.role_default['foo']['bar']['thing'] = 'otherstuff'
+```
+
+And a force attribute:
+
+```ruby
+node.force_default['foo']['bar']['thing'] = 'allthestuff'
+```
+
+When the default attribute precedence `node['foo']['bar']` is removed:
+
+```ruby
+node.rm_default('foo', 'bar') #=> {'baz' => 52, 'thing' => 'allthestuff'}
+```
+
+What's left under `'foo'` is only `'bat'`:
+
+```ruby
+node.attributes.combined_default['foo'] #=> {'bat' => { 'things' => [5,6] } }
+```
+
+**Delete default without touching higher precedence attributes**
+
+Given the following code structure:
+
+```ruby
+node.default['foo'] = {
+ 'bar' => {
+ 'baz' => 52,
+ 'thing' => 'stuff',
+ },
+ 'bat' => {
+ 'things' => [5, 6],
+ },
+}
+```
+
+And some role attributes:
+
+```ruby
+# Please don't ever do this in real code :)
+node.role_default['foo']['bar']['thing'] = 'otherstuff'
+```
+
+And a force attribute:
+
+```ruby
+node.force_default['foo']['bar']['thing'] = 'allthestuff'
+```
+
+And also some override attributes:
+
+```ruby
+node.override['foo']['bar']['baz'] = 99
+```
+
+Same delete as before:
+
+```ruby
+node.rm_default('foo', 'bar') #=> { 'baz' => 52, 'thing' => 'allthestuff' }
+```
+
+The other attribute precedence levels are unaffected:
+
+```ruby
+node.attributes.combined_override['foo'] #=> { 'bar' => {'baz' => 99} }
+node['foo'] #=> { 'bar' => {'baz' => 99}, 'bat' => { 'things' => [5,6] }
+```
+
+**Delete override without touching lower precedence attributes**
+
+Given the following code structure, which has an override attribute:
+
+```ruby
+node.override['foo'] = {
+ 'bar' => {
+ 'baz' => 52,
+ 'thing' => 'stuff',
+ },
+ 'bat' => {
+ 'things' => [5, 6],
+ },
+}
+```
+
+with a single default value:
+
+```ruby
+node.default['foo']['bar']['baz'] = 11
+```
+
+and a force at each attribute precedence:
+
+```ruby
+node.force_default['foo']['bar']['baz'] = 55
+node.force_override['foo']['bar']['baz'] = 99
+```
+
+Delete the override:
+
+```ruby
+node.rm_override('foo', 'bar') #=> { 'baz' => 99, 'thing' => 'stuff' }
+```
+
+The other attribute precedence levels are unaffected:
+
+```ruby
+node.attributes.combined_default['foo'] #=> { 'bar' => {'baz' => 55} }
+```
+
+**Non-existent key deletes return nil**
+
+```ruby
+node.rm_default("no", "such", "thing") #=> nil
+```
+
+### Remove All Levels
+
+All attribute precedence levels may be removed by using the following
+syntax pattern:
+
+- `node.rm('foo', 'bar')`
+
+{{< note >}}
+
+Using `node['foo'].delete('bar')` will throw an exception that points to
+the new API.
+
+{{< /note >}}
+
+#### Examples
+
+The following examples show how to remove all attribute precedence
+levels.
+
+**Delete all attribute precedence levels**
+
+Given the following code structure:
+
+```ruby
+node.default['foo'] = {
+ 'bar' => {
+ 'baz' => 52,
+ 'thing' => 'stuff',
+ },
+ 'bat' => {
+ 'things' => [5, 6],
+ },
+}
+```
+
+With override attributes:
+
+```ruby
+node.override['foo']['bar']['baz'] = 999
+```
+
+Removing the `'bar'` key returns the computed value:
+
+```ruby
+node.rm('foo', 'bar') #=> {'baz' => 999, 'thing' => 'stuff'}
+```
+
+Looking at `'foo'`, all that's left is the `'bat'` entry:
+
+```ruby
+node['foo'] #=> {'bat' => { 'things' => [5,6] } }
+```
+
+**Non-existent key deletes return nil**
+
+```ruby
+node.rm_default("no", "such", "thing") #=> nil
+```
+
+### Full Assignment
+
+Use `!` to clear out the key for the named attribute precedence level,
+and then complete the write by using one of the following syntax
+patterns:
+
+- `node.default!['foo']['bar'] = {...}`
+- `node.force_default!['foo']['bar'] = {...}`
+- `node.normal!['foo']['bar'] = {...}`
+- `node.override!['foo']['bar'] = {...}`
+- `node.force_override!['foo']['bar'] = {...}`
+
+#### Examples
+
+The following examples show how to remove all attribute precedence
+levels.
+
+**Just one component**
+
+Given the following code structure:
+
+```ruby
+node.default['foo']['bar'] = {'a' => 'b'}
+node.default!['foo']['bar'] = {'c' => 'd'}
+```
+
+The `'!'` caused the entire 'bar' key to be overwritten:
+
+```ruby
+node['foo'] #=> {'bar' => {'c' => 'd'}
+```
+
+**Multiple components; one "after"**
+
+Given the following code structure:
+
+```ruby
+node.default['foo']['bar'] = {'a' => 'b'}
+# Please don't ever do this in real code :)
+node.role_default['foo']['bar'] = {'c' => 'd'}
+node.default!['foo']['bar'] = {'d' => 'e'}
+```
+
+The `'!'` write overwrote the "cookbook-default" value of `'bar'`, but
+since role data is later in the resolution list, it was unaffected:
+
+```ruby
+node['foo'] #=> {'bar' => {'c' => 'd', 'd' => 'e'}
+```
+
+**Multiple components; all "before"**
+
+Given the following code structure:
+
+```ruby
+node.default['foo']['bar'] = {'a' => 'b'}
+# Please don't ever do this in real code :)
+node.role_default['foo']['bar'] = {'c' => 'd'}
+node.force_default!['foo']['bar'] = {'d' => 'e'}
+```
+
+With `force_default!` there is no other data under `'bar'`:
+
+```ruby
+node['foo'] #=> {'bar' => {'d' => 'e'}
+```
+
+**Multiple precedence levels**
+
+Given the following code structure:
+
+```ruby
+node.default['foo'] = {
+ 'bar' => {
+ 'baz' => 52,
+ 'thing' => 'stuff',
+ },
+ 'bat' => {
+ 'things' => [5, 6],
+ },
+}
+```
+
+And some attributes:
+
+```ruby
+# Please don't ever do this in real code :)
+node.role_default['foo']['bar']['baz'] = 55
+node.force_default['foo']['bar']['baz'] = 66
+```
+
+And other precedence levels:
+
+```ruby
+node.normal['foo']['bar']['baz'] = 88
+node.override['foo']['bar']['baz'] = 99
+```
+
+With a full assignment:
+
+```ruby
+node.default!['foo']['bar'] = {}
+```
+
+Role default and force default are left in default, plus other
+precedence levels:
+
+```ruby
+node.attributes.combined_default['foo'] #=> {'bar' => {'baz' => 66}, 'bat'=>{'things'=>[5, 6]}}
+node.attributes.normal['foo'] #=> {'bar' => {'baz' => 88}}
+node.attributes.combined_override['foo'] #=> {'bar' => {'baz' => 99}}
+node['foo']['bar'] #=> {'baz' => 99}
+```
+
+If `force_default!` is written:
+
+```ruby
+node.force_default!['foo']['bar'] = {}
+```
+
+the difference is:
+
+```ruby
+node.attributes.combined_default['foo'] #=> {'bat'=>{'things'=>[5, 6]}, 'bar' => {}}
+node.attributes.normal['foo'] #=> {'bar' => {'baz' => 88}}
+node.attributes.combined_override['foo'] #=> {'bar' => {'baz' => 99}}
+node['foo']['bar'] #=> {'baz' => 99}
+```
diff --git a/content/cookbooks/attributes/attribute_sources.md b/content/cookbooks/attributes/attribute_sources.md
new file mode 100644
index 0000000..78e82fc
--- /dev/null
+++ b/content/cookbooks/attributes/attribute_sources.md
@@ -0,0 +1,144 @@
++++
+title = "Attribute Sources"
+draft = false
+
+[menu]
+ [menu.cookbooks]
+ title = "Attribute Sources"
+ identifier = "cookbooks/attributes/attribute_sources Attributes"
+ parent = "cookbooks/attributes"
++++
+
+
+Chef Infra Client evaluates attributes in the order that they're defined in the
+run-list, including any attributes that are in the run-list as
+cookbook dependencies.
+
+Attributes are provided to Chef Infra Client from the following
+locations:
+
+- JSON files passed using the `chef-client -j`
+- Nodes (collected by Ohai at the start of each Chef Infra Client run)
+- Attribute files (in cookbooks)
+- Recipes (in cookbooks)
+- Environments
+- Roles
+- Policyfiles
+
+Notes:
+
+- Many attributes are maintained in the chef-repo for Policyfiles,
+ environments, roles, and cookbooks (attribute files and recipes)
+- Many attributes are collected by Ohai on each individual node at the
+ start of every Chef Infra Client run
+- The attributes that are maintained in the chef-repo are uploaded to
+ Chef Infra Server from the workstation, periodically
+- Chef Infra Client will pull down the node object from the Chef Infra
+ Server and then reset all the attributes except `normal`. The node
+ object will contain the attribute data from the previous Chef Infra
+ Client run including attributes set with JSON files using `-j`.
+- Chef Infra Client will update the cookbooks on the node (if
+ required), which updates the attributes contained in attribute files
+ and recipes
+- Chef Infra Client will update the role and environment data (if
+ required)
+- Chef Infra Client will rebuild the attribute list and apply
+ attribute precedence while configuring the node
+- Chef Infra Client pushes the node object to Chef Infra Server at
+ the end of a Chef Infra Client run; the updated node object on the
+ Chef Infra Server is then indexed for search and is stored until the
+ next Chef Infra Client run
+
+## Automatic Attributes (Ohai)
+
+{{< readfile file="content/reusable/md/ohai_automatic_attribute.md" >}}
+
+{{< readfile file="content/reusable/md/ohai_attribute_list.md" >}}
+
+## Attribute Files
+
+An attribute file is located in the `attributes/` sub-directory for a
+cookbook. When a cookbook is run against a node, the attributes
+contained in all attribute files are evaluated in the context of the
+node object. Node methods (when present) are used to set attribute
+values on a node. For example, the `apache2` cookbook contains an
+attribute file called `default.rb`, which contains the following
+attributes:
+
+```ruby
+default['apache']['dir'] = '/etc/apache2'
+default['apache']['listen_ports'] = [ '80','443' ]
+```
+
+The use of the node object (`node`) is implicit in the previous example;
+the following example defines the node object itself as part of the
+attribute:
+
+```ruby
+node.default['apache']['dir'] = '/etc/apache2'
+node.default['apache']['listen_ports'] = [ '80','443' ]
+```
+
+Another (much less common) approach is to set a value only if an
+attribute has no value. This can be done by using the `_unless` variants
+of the attribute priority methods:
+
+- `default_unless`
+- `normal_unless`
+
+Use the `_unless` variants carefully (and only when necessary) because
+when they're used, attributes applied to nodes may become out of sync
+with the values in the cookbooks as these cookbooks are updated. This
+approach can create situations where two otherwise identical nodes end
+up having slightly different configurations and can also be a challenge
+to debug.
+
+### File Methods
+
+Use the following methods within the attributes file for a cookbook or within a recipe. These methods correspond to the attribute type of the same name:
+
+- `override`
+- `default`
+- `normal`
+- `_unless`
+
+### attribute?
+
+A useful method that's related to attributes is the `attribute?`
+method. This method will check for the existence of an attribute, so
+that processing can be done in an attributes file or recipe, but only if
+a specific attribute exists.
+
+Using `attribute?()` in an attributes file:
+
+```ruby
+if attribute?('ec2')
+ # ... set stuff related to EC2
+end
+```
+
+Using `attribute?()` in a recipe:
+
+```ruby
+if node.attribute?('ec2')
+ # ... do stuff on EC2 nodes
+end
+```
+
+## Attributes from Recipes
+
+{{< readfile file="content/reusable/md/cookbooks_recipe.md" >}}
+
+{{< readfile file="content/reusable/md/cookbooks_attribute.md" >}}
+
+## Attributes from Roles
+
+{{< readfile file="content/reusable/md/role.md" >}}
+
+{{< readfile file="content/reusable/md/role_attribute.md" >}}
+
+## Attributes from Environments
+
+{{< readfile file="content/reusable/md/environment.md" >}}
+
+{{< readfile file="content/reusable/md/environment_attribute.md" >}}
diff --git a/content/cookbooks/attributes/attribute_types.md b/content/cookbooks/attributes/attribute_types.md
new file mode 100644
index 0000000..8e41423
--- /dev/null
+++ b/content/cookbooks/attributes/attribute_types.md
@@ -0,0 +1,34 @@
++++
+title = "Attribute Types"
+draft = false
+
+[menu]
+ [menu.cookbooks]
+ title = "Attribute Types"
+ identifier = "cookbooks/attributes/attributes_types.md Attributes"
+ parent = "cookbooks/attributes"
++++
+
+Chef Infra Client uses six types of attributes to determine the value that's applied to a node during a Chef Infra Client run.
+In addition, Chef Infra Client gathers attribute values from up to five locations.
+The combination of attribute types and sources makes up to 15 different competing values available during a Chef Infra Client run.
+
+The attribute types are:
+
+`default`
+: {{< readfile file="content/reusable/md/node_attribute_type_default.md" >}}
+
+`force_default`
+: Use the force_default attribute to ensure that an attribute defined in a cookbook (by an attribute file or by a recipe) takes precedence over a default attribute set by a role or an environment.
+
+`normal`
+: {{< readfile file="content/reusable/md/node_attribute_type_normal.md" >}}
+
+`override`
+: {{< readfile file="content/reusable/md/node_attribute_type_override.md" >}}
+
+`force_override`
+: Use the force_override attribute to ensure that an attribute defined in a cookbook (by an attribute file or by a recipe) takes precedence over an override attribute set by a role or an environment.
+
+`automatic`
+: {{< readfile file="content/reusable/md/node_attribute_type_automatic.md" >}}
diff --git a/content/cookbooks/chef_repo/_index.md b/content/cookbooks/chef_repo/_index.md
new file mode 100644
index 0000000..517f0f6
--- /dev/null
+++ b/content/cookbooks/chef_repo/_index.md
@@ -0,0 +1,116 @@
++++
+title = "About chef-repo"
+draft = false
+
+[menu]
+ [menu.chef_repo]
+ title = "About chef-repo"
+ identifier = "chef_repo/chef_repo.md"
+ parent = "chef_repo"
+ weight = 15
++++
+
+{{< readfile file="content/reusable/md/chef_repo_description.md" >}}
+
+## Generate the chef-repo
+
+Use the [chef generate repo command](https://docs.chef.io/workstation/ctl_chef/#chef-generate-repo) to create your chef-repo directory along with the base folder structure. This command uses the `chef` command-line tool that's packaged as part of Chef Workstation to create a chef-repo.
+
+```bash
+chef generate repo REPO_NAME
+```
+
+{{< note >}}
+
+`chef generate repo` generates a chef-repo that's configured for Policyfiles by default. To create a repository that's setup for Roles and Environments use the `--roles` flag when running the command.
+
+{{< /note >}}
+
+## Directory structure
+
+The chef-repo contains several directories, each with a README file that describes what it's for and how to use that directory when managing systems.
+
+The default structure of a new chef-repo is:
+
+```plain
+. chef-repo
+├── LICENSE
+├── README.md
+├── chefignore
+├── cookbooks
+│ ├── README.md
+│ └── example
+│ ├── README.md
+│ ├── attributes
+│ │ ├── README.md
+│ │ └── default.rb
+│ ├── metadata.rb
+│ └── recipes
+│ ├── README.md
+│ └── default.rb
+├── data_bags
+│ ├── README.md
+│ └── example
+│ ├── README.md
+│ └── example_item.json
+└── policyfiles
+ └── README.md
+```
+
+### cookbooks
+
+The `cookbooks` directory contains cookbooks that configure systems in the infrastructure which are are downloaded from the [Chef Supermarket](https://supermarket.chef.io/) or created locally. The Chef Infra Client uses cookbooks to configuring the systems in the organization. Each cookbook can be configured to contain cookbook-specific copyright, email, and license data.
+
+### data_bags
+
+The `data_bags` directory is used to store all the data bags that exist for an organization. Each sub-directory corresponds to a single data bag on Chef Infra Server and contains a JSON file corresponding to each data bag item.
+
+### policyfiles
+
+The `policyfiles` directory is used to store Policyfiles in the `.rb` format that define the set of cookbooks and attributes to apply to specific systems managed by Chef Infra Server.
+
+### chefignore
+
+A `chefignore` file tells knife which cookbook files in the chef-repo it should ignore when uploading data to Chef Infra Server.
+Include swap files, version control data, and build output data in a `chefignore` file.
+
+The `chefignore` file has the following rules:
+
+- Patterns use `*`, `**`, and `?` wildcards to match files and directories as defined by the `File.fnmatch` Ruby method.
+- A pattern is relative to the directory it's included in.
+- A pattern may contain relative directory names.
+- A pattern may match all files in a directory.
+- You can add a `chefignore` file to any subdirectory of a chef-repo. For example, `/`, `/cookbooks`, `/cookbooks/COOKBOOK_NAME/`, etc.
+- Lines that start with `#` are comments.
+
+Group types of ignored files in sections similar to the following:
+
+```plain
+## OS generated files
+*ignore_pattern
+
+## Editors
+another_ignore_pattern*
+```
+
+See Ruby's [`File.fnmatch` documentation](https://ruby-doc.org/core-2.5.1/File.html#method-c-fnmatch) for information on creating matching file patterns.
+
+#### Examples
+
+Many text editors leave files behind. To prevent knife from uploading these files to Chef Infra Server, add an entry to the `chefignore` file.
+
+For Emacs backup files:
+
+```plain
+*~
+```
+
+and for Vim swap files:
+
+```plain
+*.sw[a-z]
+```
+
+## Many Users, Same Repo
+
+{{< readfile file="content/reusable/md/chef_repo_many_users_same_knife.md" >}}
diff --git a/content/cookbooks/config_rb_metadata.md b/content/cookbooks/config_rb_metadata.md
new file mode 100644
index 0000000..b059afd
--- /dev/null
+++ b/content/cookbooks/config_rb_metadata.md
@@ -0,0 +1,290 @@
++++
+title = "metadata.rb"
+draft = false
+
+[menu]
+ [menu.cookbooks]
+ title = "metadata.rb"
+ identifier = "cookbooks/config_rb_metadata.md metadata.rb Configuration"
+ parent = "cookbooks"
+ weight = 60
++++
+
+
+
+{{< readfile file="content/reusable/md/cookbooks_metadata.md" >}}
+
+* Located at the top level of a cookbook's directory structure.
+* Compiled whenever a cookbook is uploaded to Chef Infra Server or when the `knife cookbook metadata` subcommand is run, and then stored as JSON data.
+* Created automatically by knife whenever the `knife cookbook create` subcommand is run.
+* Edited using a text editor, and then re-uploaded to Chef Infra Server as part of a cookbook upload.
+
+## Error Messages
+
+Chef Infra Server will only try to distribute the cookbooks that are needed to configure an individual node. This is determined by identifying the roles and recipes that are assigned directly to that system, and then to expand the list of dependencies, and then to deliver that entire set to the node. In some cases, if the dependency isn't specified in the cookbook's metadata, Chef Infra Server may not treat that dependency as a requirement, which will result in an error message. If an error message is received from Chef Infra Server about cookbook distribution, verify the `depends` entries in the `metadata.rb` file, and then try again.
+
+{{< note >}}
+
+A metadata.json file can be edited directly, should temporary changes be required. Any subsequent upload or action that generates metadata will cause the existing metadata.json file to be overwritten with the newly generated metadata. Therefore, any permanent changes to cookbook metadata should be done in the `metadata.rb` file, and then re-uploaded to Chef Infra Server.
+
+{{< /note >}}
+
+## Version Constraints
+
+Many fields in a cookbook's metadata allow the user to constrain versions. The following operators are common to all fields:
+
+
+
+
+
+
+
+
+
+
+
+
+| Pessimistic (see note below) |
+~> |
+
+
+| Equal to |
+= |
+
+
+| Greater than or equal to |
+>= |
+
+
+| Greater than |
+> |
+
+
+| Less than |
+< |
+
+
+| Less than or equal to |
+<= |
+
+
+
+
+
+{{< note >}}
+
+Pessimistic locking is enabled by proper [semantic versioning](https://semver.org) of cookbooks. If we're on version 2.2.3 of a cookbook, we know that the API will be stable until the 3.0.0 release. Using traditional operators, we'd write this as `>= 2.2.0, < 3.0`. Instead, we can write this by combining a tilde "\~" and right angle bracket "\>"--often called a tilde-rocket or "twiddle-wakka"--followed by the major and minor version numbers. For example: `~> 2.2`
+
+{{< /note >}}
+
+## Settings
+
+This configuration file has the following settings:
+
+`chef_version`
+
+: A range of Chef Infra Client versions that are supported by this cookbook. All [version constraint operators](#version-constraints) are applicable to this field.
+
+ For example, to match any 16.x version of the Chef Infra Client, but not 15.x or 17.x:
+
+ ```ruby
+ chef_version '~> 16.0'
+ ```
+
+ A more complex example where you set both a lower and upper bound of the Chef Infra Client version:
+
+ ```ruby
+ chef_version '>= 17.2', '< 17.4'
+ ```
+
+`depends`
+
+: This field requires that a cookbook with a matching name and version exists on Chef Infra Server. When the match exists, Chef Infra Server includes the dependency as part of the set of cookbooks that are sent to the node during a Chef Infra Client run. It's important that the `depends` field contain accurate data. If a dependency statement is inaccurate, Chef Infra Client may not be able to complete the configuration of the system. All [version constraint operators](#version-constraints) are applicable to this field.
+
+ For example, to set a dependency a cookbook named `cats`:
+
+ ```ruby
+ depends 'cats'
+ ```
+
+ or, to set a dependency on the same cookbook, but only when the version is less than 1.0:
+
+ ```ruby
+ depends 'cats', '< 1.0'
+ ```
+
+`description`
+
+: A short description of a cookbook and its functionality.
+
+ For example:
+
+ ```ruby
+ description 'A fancy cookbook that manages a herd of cats!'
+ ```
+
+`gem`
+
+: Specifies a gem dependency for installation in Chef Infra Client through bundler. The gem installation occurs after all cookbooks are synchronized but before loading any other cookbooks. Use this attribute one time for each gem dependency. For example:
+
+ ```ruby
+ gem 'loofah'
+ gem 'chef-sugar'
+ ```
+
+ {{< warning >}}
+
+ Use the `gem` setting only for making external chef libraries shipped as gems accessible in a Chef Infra Client run for libraries and attribute files. The `gem` setting in `metadata.rb` allows for the early installation of this specific type of gem, with the fundamental limitation that it can't install native gems.
+
+ Don't install native gems with the `gem` setting in `metadata.rb`. The `gem` setting isn't a general purpose replacement for the [chef_gem resource](/resources/bundled/chef_gem/), and doesn't internally re-use the `chef_gem` resource. Native gems require C compilation and must not be installed with `metadata.rb` because `metadata.rb` runs before any recipe code runs. Consequently, Chef Infra Client Linux install the C compilers before the gem installation occurs. Instead, install native gems with the `chef_gem` resource called from the recipe code. You'll also need to use the `build_essential` resource in the recipe code to install the prerequisite compilers onto the system.
+
+ Pure ruby gems can also be installed with `metadata.rb`.
+
+ {{< /warning >}}
+
+`issues_url`
+
+: The URL of the location in which a cookbook's issue tracking is maintained. This setting is also used by Chef Supermarket. In Chef Supermarket, this value is used to define the destination for the "View Issues" link.
+
+ For example:
+
+ ```ruby
+ issues_url 'https://github.com/chef-cookbooks/chef-client/issues'
+ ```
+
+`license`
+
+: The type of license under which a cookbook is distributed: `Apache v2.0`, `GPL v2`, `GPL v3`, `MIT`, or `license 'Proprietary - All Rights Reserved` (default). Please be aware of the licenses for files inside of a cookbook and be sure to follow any restrictions they describe.
+
+ For example:
+
+ ```ruby
+ license 'Apache-2.0'
+ ```
+
+ or:
+
+ ```ruby
+ license 'GPL-3.0'
+ ```
+
+ or:
+
+ ```ruby
+ license 'MIT'
+ ```
+
+ or:
+
+ ```ruby
+ license 'Proprietary - All Rights Reserved'
+ ```
+
+`maintainer`
+
+: The name of the person responsible for maintaining a cookbook, either an individual or an organization.
+
+ For example:
+
+ ```ruby
+ maintainer 'Bob Bobberson'
+ ```
+
+`maintainer_email`
+
+: The email address for the person responsible for maintaining a cookbook. Only one email can be listed here, so if this needs to be forwarded to multiple people consider using an email address that's already setup for mail forwarding.
+
+ For example:
+
+ ```ruby
+ maintainer_email 'bob@example.com'
+ ```
+
+`name`
+
+: Required. The name of the cookbook.
+
+ For example:
+
+ ```ruby
+ name 'cats'
+ ```
+
+`ohai_version`
+
+: A range of Ohai versions that are supported by this cookbook. All [version constraint operators](#version-constraints) are applicable to this field.
+
+ For example, to match any 8.x version of Ohai, but not 7.x or 9.x:
+
+ ```ruby
+ ohai_version '~> 8'
+ ```
+
+ {{< note >}}
+
+ This setting isn't visible in Chef Supermarket.
+
+ {{< /note >}}
+
+`privacy`
+
+: Specify a cookbook as private. This prevents a cookbook from being uploaded to the public Supermarket or any Supermarket where ``ENFORCE_PRIVACY`` has been enabled.
+
+ For example:
+
+ ```ruby
+ privacy true
+ ```
+
+`source_url`
+
+: The URL of the location in which a cookbook's source code is maintained. This setting is also used by Chef Supermarket. In Chef Supermarket, this value is used to define the destination for the "View Source" link.
+
+ For example:
+
+ ```ruby
+ source_url 'https://github.com/chef-cookbooks/chef-client'
+ ```
+
+`supports`
+
+: Show that a cookbook has a supported platform. Use a version constraint to define dependencies for platform versions: `<` (less than), `<=` (less than or equal to), `=` (equal to), `>=` (greater than or equal to), `~>` (approximately greater than), or `>` (greater than). To specify more than one platform, use more than one `supports` field, once for each platform.
+
+ For example, to support every version of Ubuntu:
+
+ ```ruby
+ supports 'ubuntu'
+ ```
+
+ or, to support versions of Ubuntu greater than or equal to 20.04:
+
+ ```ruby
+ supports 'ubuntu', '>= 20.04'
+ ```
+
+ or, to support only Ubuntu 20.04:
+
+ ```ruby
+ supports 'ubuntu', '= 20.04'
+ ```
+
+ Here is a list of all of the supported specific operating systems:
+
+ ```ruby
+ %w( aix amazon centos fedora freebsd debian oracle mac_os_x redhat suse opensuseleap ubuntu windows zlinux ).each do |os|
+ supports os
+ end
+ ```
+
+`version`
+
+: The current version of a cookbook. Version numbers always follow a simple three-number version sequence.
+
+ For example:
+
+ ```ruby
+ version '2.0.0'
+ ```
diff --git a/content/cookbooks/cookbook_repo.md b/content/cookbooks/cookbook_repo.md
new file mode 100644
index 0000000..a869e53
--- /dev/null
+++ b/content/cookbooks/cookbook_repo.md
@@ -0,0 +1,130 @@
++++
+title = "Get Started"
+draft = false
+
+[menu]
+ [menu.cookbooks]
+ title = "Cookbook Directory"
+ identifier = "cookbooks/cookbook_repo.md Cookbook Repo"
+ parent = "cookbooks"
+ weight = 20
++++
+
+The `cookbooks/` directory of your Chef Infra repository is used to
+store the cookbooks that Chef Infra Client uses in configuring the
+various systems in the organization.
+
+## Chef Repository
+
+The the `\cookbook` directory is automatically generated as part of your Chef Infra repository.
+
+```bash
+chef generate repo REPO_NAME
+```
+
+### Cookbook Directory Structure
+
+The default structure of the cookbooks directory is:
+
+```plain
+. chef-repo
+└── cookbooks
+ ├── README.md
+ └── example
+ ├── README.md
+ ├── attributes
+ │ ├── README.md
+ │ └── default.rb
+ ├── metadata.rb
+ └── recipes
+ ├── README.md
+ └── default.rb
+```
+
+## Cookbook Commands
+
+Use the following commands to create a cookbook, install a cookbook from Supermarket, and/or download cookbooks.
+
+### Create
+
+Chef Workstation generates the `cookbooks` directory as part of your Chef Infra repository, the `chef-repo`.
+
+Generate a `chef-repo/cookbooks` directory with the command:
+
+```bash
+chef generate template PATH_TO_COOKBOOKS COOKBOOK_NAME
+```
+
+For example, this command generates a `custom_web` cookbook:
+
+```bash
+chef generate cookbook cookbooks/custom_web
+```
+
+The `custom_web` cookbook directory has the structure:
+
+```text
+. cookbooks
+└── custom_web
+ ├── CHANGELOG.md
+ ├── LICENSE
+ ├── Policyfile.rb
+ ├── README.md
+ ├── chefignore
+ ├── compliance
+ │ ├── README.md
+ │ ├── inputs
+ │ ├── profiles
+ │ └── waivers
+ ├── kitchen.yml
+ ├── metadata.rb
+ ├── recipes
+ │ └── default.rb
+ └── test
+ └── integration
+ └── default
+ └── default_test.rb
+```
+
+Any unneeded directory components can be left unused or deleted, if
+preferred.
+
+### Install
+
+To download a cookbook when git is used for version source control, run
+the following command:
+
+```bash
+knife supermarket install COOKBOOK_NAME
+```
+
+where `COOKBOOK_NAME` is the name of a cookbook on [Chef
+Supermarket](https://supermarket.chef.io/). This will start a process
+that:
+
+- downloads the cookbook from [Chef Supermarket](https://supermarket.chef.io/) as a `tar.gz` archive
+- ensures that its using the git main branch, and then checks out
+ the cookbook from a vendor branch (creating a new vendor branch, if
+ required)
+- removes the old (existing) version
+- expands the tar.gz archive and adds the expanded files to the git
+ index and commits
+- creates a tag for the version that was downloaded
+- checks out the main branch
+- merges the cookbook into the main branch (to ensure that any local
+ changes or modifications are preserved)
+
+### Download
+
+To download a cookbook when git isn't used for version source control,
+run the following command:
+
+```bash
+knife supermarket download COOKBOOK_NAME
+```
+
+where `COOKBOOK_NAME` is the name of a cookbook on [Chef
+Supermarket](https://supermarket.chef.io/). This will download the
+tar.gz file associated with the cookbook and will create a file named
+`COOKBOOK_NAME.tar.gz` in the current directory (`~/chef-repo`).
+Once downloaded, using a version source control system is recommended.
diff --git a/content/cookbooks/cookbook_versioning.md b/content/cookbooks/cookbook_versioning.md
new file mode 100644
index 0000000..62ddc3f
--- /dev/null
+++ b/content/cookbooks/cookbook_versioning.md
@@ -0,0 +1,343 @@
++++
+title = "About cookbook versioning"
+draft = false
+
+[menu]
+ [menu.cookbooks]
+ title = "Versioning cookbooks"
+ identifier = "cookbooks/cookbook_versioning.md Versioning Cookbooks"
+ parent = "cookbooks"
+ weight = 150
++++
+
+
+
+{{< readfile file="content/reusable/md/cookbooks_version.md" >}}
+
+## Syntax
+
+A cookbook version always takes the form x.y.z, where x, y, and z are
+decimal numbers that are used to represent major (x), minor (y), and
+patch (z) versions. A two-part version (x.y) is also allowed.
+Alphanumeric version numbers (1.2.a3) and version numbers with more than
+three parts (1.2.3.4) aren't allowed.
+
+## Constraints
+
+A version constraint is a string that combines the cookbook version
+syntax with an operator, in the following format:
+
+```ruby
+operator cookbook_version_syntax
+```
+
+{{< note >}}
+
+Single digit cookbook versions aren't allowed. Cookbook versions must
+specify at least the major and minor version. For example, use `1.0` or
+`1.0.1`; don't use `1`.
+
+{{< /note >}}
+
+{{< readfile file="content/reusable/md/cookbooks_version_constraints_operators.md" >}}
+
+For example, a version constraint for "equals version 1.0.7" is
+expressed like this:
+
+```ruby
+= 1.0.7
+```
+
+A version constraint for "greater than version 1.0.2" is expressed like
+this:
+
+```ruby
+> 1.0.2
+```
+
+An optimistic version constraint is one that looks for versions greater
+than or equal to the specified version. For example:
+
+```ruby
+>= 2.6.5
+```
+
+will match cookbooks greater than or equal to 2.6.5, such as 2.6.5,
+2.6.7 or 3.1.1.
+
+A pessimistic version constraint is one that will find the upper limit
+version number within the range specified by the minor version number or
+patch version number. For example, a pessimistic version constraint for
+minor version numbers:
+
+```ruby
+~> 2.6
+```
+
+will match cookbooks that are greater than or equal to version 2.6, but
+less than version 3.0.
+
+Or, a pessimistic version constraint for patch version numbers:
+
+```ruby
+~> 2.6.5
+```
+
+will match cookbooks that are greater than or equal to version 2.6.5,
+but less than version 2.7.0.
+
+Or, a pessimistic version constraint that matches cookbooks less than a
+version number:
+
+```ruby
+< 2.3.4
+```
+
+or will match cookbooks less than or equal to a specific version number:
+
+```ruby
+<= 2.6.5
+```
+
+## Metadata
+
+{{< readfile file="content/reusable/md/cookbooks_metadata.md" >}}
+
+Versions and version constraints can be specified in a cookbook's `metadata.rb` file by using the following functions.
+Each function accepts a name and an optional version constraint.
+If a version constraint isn't provided, `>= 0.0.0` is used as the default.
+
+
+
+`depends`
+: Specify that a cookbook has a dependency on another cookbook.
+ You can use a version constraint to define dependencies for cookbook versions:
+
+ - `<`: less than
+ - `<=`: less than or equal to
+ - `=`: equal to
+ - `>=`: greater than or equal to---also known as optimistically greater than or optimistic.
+ - `~>`: approximately greater than---also known as pessimistically greater than or pessimistic
+ - `>`: greater than
+
+ A cookbook with a matching name and version must exist on Chef Infra Server.
+ When the match exists, Chef Infra Server includes the dependency as part of the set of cookbooks that are sent to the node when Chef Infra Client runs.
+
+ The `depends` field must contain accurate data.
+ If a dependency statement is inaccurate, Chef Infra Client may not be able to complete the configuration of the system.
+
+ For example:
+
+ ```ruby
+ depends 'opscode-base'
+ ```
+
+ or:
+
+ ```ruby
+ depends 'opscode-github', '> 1.0.0'
+ ```
+
+ or:
+
+ ```ruby
+ depends 'runit', '~> 1.2.3'
+ ```
+
+`provides`
+: Add a recipe, definition, or resource that's provided by this cookbook if the populated list is insufficient.
+
+`supports`
+: Specify that a cookbook has a supported platform.
+
+ You can use a version constraint to define dependencies for platform versions:
+
+ - `<`: less than
+ - `<=`: less than or equal to
+ - `=`: equal to
+ - `>=`: greater than or equal to
+ - `~>`: approximately greater than
+ - `>`: greater than
+
+ To specify more than one platform, use more than one `supports` field, once for each platform.
+
+## Environments
+
+An environment can use version constraints to specify a list of allowed
+cookbook versions by specifying the cookbook's name, along with the
+version constraint. For example:
+
+```ruby
+cookbook 'apache2', '~> 1.2.3'
+```
+
+Or:
+
+```ruby
+cookbook 'runit', '= 4.2.0'
+```
+
+If a cookbook isn't explicitly given a version constraint the
+environment will assume the cookbook has no version constraint and will
+use any version of that cookbook with any node in the environment.
+
+## Freeze versions
+
+A cookbook version can be frozen, which will prevent updates from being
+made to that version of a cookbook. (A user can always upload a new
+version of a cookbook.) Using cookbook versions that are frozen within
+environments is a reliable way to keep a production environment safe
+from accidental updates while testing changes that are made to a
+development infrastructure.
+
+For example, to freeze a cookbook version using knife, enter:
+
+```bash
+knife cookbook upload redis --freeze
+```
+
+To return:
+
+```bash
+Uploading redis...
+Upload completed
+```
+
+Once a cookbook version is frozen, only by using the `--force` option
+can an update be made. For example:
+
+```bash
+knife cookbook upload redis --force
+```
+
+Without the `--force` option specified, an error will be returned
+similar to:
+
+```bash
+Version 0.0.0 of cookbook redis is frozen. Use --force to override
+```
+
+## Managing Many Cookbook Versions
+
+{{< warning >}}
+
+If you continually upload all versions of many cookbooks to your Chef Infra Server, you may overload Chef Infra Server's dependency solver, causing it to time out and leading to a failed Chef Infra Client run.
+
+There are three solutions to this problem:
+
+- use [Policyfiles](/policy/policyfile/) (recommended)
+- place version constraints on all cookbooks and all dependencies of all cookbooks in any run list you use for a Chef Infra Client run
+- upload only the required cookbook versions to a Chef Infra Server
+
+{{< /warning >}}
+
+In a CI/CD workflow where new cookbook versions are continually uploaded to a Chef Infra Server, the Chef Infra Server dependency solver must look at more and more cookbook versions while trying to solve the constraints given to it from the run list of each Chef Infra Client that starts up. Eventually, it runs out of time to produce a solution, times out, and the Chef Infra Client run fails as a result. Chef Infra Server may also pick older cookbook versions than the versions that you intended.
+
+The dependency solver workers in a Chef Infra Server have a default timeout of five seconds. The solution isn't to increase their timeout, but to control the problem so that the dependency solvers can solve it in a reasonable amount of time.
+
+### Policyfiles
+
+The current best practice is to control cookbook versions through Policyfiles. In this way, the dependency resolution is shifted left to the cookbook author designing the cookbook, its dependency structure, and the needed versions of all involved cookbooks. See the [Policyfiles](/policy/policyfile/) documentation for more information.
+
+### Version Constraints
+
+In a CI/CD environment where you have many versions of cookbooks, place version constraints on all cookbooks and all dependencies of all cookbooks in any run list you use for a Chef Infra Client run.
+
+The way to control the problem traditionally is by pinning the versions of cookbooks in an environment file or by using a wrapper cookbook that calls out the dependencies AND their versions in its `metadata.rb` file, and the dependencies do the same in their own `metadata.rb` files. See the [Cookbook Metadata Files](/cookbooks/config_rb_metadata/) for more information.
+
+### Minimum Number of Cookbook Versions
+
+The dependency solver will also work properly if you upload the minimum number of cookbook versions needed to Chef Infra Server.
+
+You can make a start at this by only uploading tested and blessed cookbook versions to your Chef Infra Server. These cookbooks would be ones where each scenario or role for the nodes is considered and that small set of cookbook versions are made available for those sets of nodes. Before Policyfiles, this policy could be implemented by constraining dependency solver access to candidate versions using an [environment]({{< relref "environments" >}}) file.
+
+## Version Source Control
+
+There are two strategies to consider when using version control as part
+of the cookbook management process:
+
+- Use maximum version control when it's important to keep every bit of data within version control
+- Use branch tracking when cookbooks are being managed in separate environments using git branches and the versioning policy information is already stored in a cookbook's metadata.
+
+### Branch Tracking
+
+Using a branch tracking strategy requires that a branch for each
+environment exists in the source control and that each cookbook's
+versioning policy is tracked at the branch level. This approach is
+relatively simple and lightweight: for development environments that
+track the latest cookbooks, just bump the version before a cookbook is
+uploaded for testing. For any cookbooks that require higher levels of
+version control, knife allows cookbooks to be uploaded to specific
+environments and for cookbooks to be frozen (which prevents others from
+being able to make changes to that cookbook).
+
+The typical workflow with a branch tracking version control strategy
+includes:
+
+1. Bumping the version number as appropriate.
+2. Making changes to a cookbook.
+3. Uploading and testing a cookbook.
+4. Moving a tested cookbook to production.
+
+For example, to bump a version number, first make changes to the
+cookbook, and then upload and test it. Repeat this process as required,
+and then upload it using a knife command similar to:
+
+```bash
+knife cookbook upload my-app
+```
+
+When the cookbook is finished, move those changes to the production
+environment and use the `--freeze` option to prevent others from making
+further changes:
+
+```bash
+knife cookbook upload my-app -E production --freeze
+```
+
+### Maximum Versions
+
+Using a maximum version control strategy is required when everything
+needs to be tracked in source control. This approach is similar to
+a branch tracking strategy while the cookbook is in development and
+being tested, but is more complicated and time-consuming (and requires
+file-level editing for environment data) to get the cookbook
+deployed to a production environment.
+
+The typical workflow with a maximum version control strategy includes:
+
+1. Bumping the version number as appropriate.
+2. Making changes to a cookbook.
+3. Uploading and testing a cookbook.
+4. Moving a tested cookbook to production.
+
+For example, to bump a version number, first make changes to the
+cookbook, and then upload and test it. Repeat this process as required,
+and then upload it using a knife command similar to:
+
+```bash
+knife cookbook upload my-app
+```
+
+When the cookbook is finished, move those changes to the production
+environment and use the `--freeze` option to prevent others from making
+further changes:
+
+```bash
+knife cookbook upload my-app -E production --freeze
+```
+
+Then modify the environment so that it prefers the newly uploaded
+version:
+
+```bash
+(vim|emacs|mate|ed) YOUR_REPO/environments/production.rb
+```
+
+Upload the updated environment:
+
+```bash
+knife environment from file production.rb
+```
+
+And then deploy the new cookbook version.
diff --git a/content/cookbooks/files.md b/content/cookbooks/files.md
new file mode 100644
index 0000000..7ddd050
--- /dev/null
+++ b/content/cookbooks/files.md
@@ -0,0 +1,15 @@
++++
+title = "Cookbook Files"
+draft = false
+
+[menu]
+ [menu.cookbooks]
+ title = "Files"
+ identifier = "cookbooks/files.md Files"
+ parent = "cookbooks"
+ weight = 40
++++
+
+The `files` directory in Chef Infra cookbooks stores files that are used
+in your cookbook with the [cookbook_file](/resources/bundled/cookbook_file/)
+resource.
diff --git a/content/cookbooks/libraries.md b/content/cookbooks/libraries.md
new file mode 100644
index 0000000..699529d
--- /dev/null
+++ b/content/cookbooks/libraries.md
@@ -0,0 +1,189 @@
++++
+title = "About Libraries"
+draft = false
+
+[menu]
+ [menu.cookbooks]
+ title = "Libraries"
+ identifier = "cookbooks/libraries.md Libraries"
+ parent = "cookbooks"
+ weight = 50
++++
+
+{{< readfile file="content/reusable/md/libraries_summary.md" >}}
+
+Use a library to:
+
+- Connect to a database
+- Fetch secrets from a cloud provider
+- Talk to an LDAP provider
+- Do anything that can be done with Ruby
+
+## Syntax
+
+The syntax for a library varies because library files are created using
+Ruby and are designed to handle custom situations. See the Examples
+section below for samples.
+
+## Template Helper Modules
+
+{{< readfile file="content/reusable/md/resource_template_library_module.md" >}}
+
+## Examples
+
+The following examples show how to use cookbook libraries.
+
+### Create a Namespace
+
+A database can contain a list of virtual hosts that are used by
+customers. A custom namespace could be created that looks something
+like:
+
+```ruby
+# Sample provided by "Arjuna (fujin)". Thank you!
+
+require 'sequel'
+
+class Chef::Recipe::ISP
+ # We can call this with ISP.vhosts
+ def self.vhosts
+ v = []
+ @db = Sequel.mysql(
+ 'web',
+ user: 'example',
+ password: 'example_pw',
+ host: 'dbserver.example.com'
+ )
+ @db[
+ "SELECT virtualhost.domainname,
+ usertable.userid,
+ usertable.uid,
+ usertable.gid,
+ usertable.homedir
+ FROM usertable, virtualhost
+ WHERE usertable.userid = virtualhost.user_name"
+ ].all do |query|
+ vhost_data = {
+ servername: query[:domainname],
+ documentroot: query[:homedir],
+ uid: query[:uid],
+ gid: query[:gid],
+ }
+ v.push(vhost_data)
+ end
+ Chef::Log.debug('About to provision #{v.length} vhosts')
+ v
+ end
+end
+```
+
+After the custom namespace is created, it could then be used in a
+recipe, like this:
+
+```ruby
+ISP.vhosts.each do |vhost|
+ directory vhost[:documentroot] do
+ owner vhost[:uid]
+ group vhost[:gid]
+ mode '0755'
+ action :create
+ end
+
+ directory "#{vhost[:documentroot]}/#{vhost[:domainname]}" do
+ owner vhost[:uid]
+ group vhost[:gid]
+ mode '0755'
+ action :create
+ end
+end
+```
+
+### Extend a Recipe
+
+A customer record is stored in an attribute file that looks like this:
+
+```ruby
+mycompany_customers({
+ bob: {
+ homedir: '/home/bob',
+ webdir: '/home/bob/web',
+ },
+}
+)
+```
+
+A simple recipe may contain something like this:
+
+```ruby
+directory node["mycompany_customers"]["bob"]["webdir"] do
+ owner 'bob'
+ group 'bob'
+ action :create
+end
+```
+
+Or a less verbose version of the same simple recipe:
+
+```ruby
+directory customer(:bob)[:webdir] do
+ owner 'bob'
+ group 'bob'
+ action :create
+end
+```
+
+A simple library could be created that extends `Chef::Recipe::`, like
+this:
+
+```ruby
+class Chef
+ class Recipe
+ # A shortcut to a customer
+ def customer(name)
+ node["mycompany_customers"][name]
+ end
+ end
+end
+```
+
+### Loop Over a Record
+
+A customer record is stored in an attribute file that looks like this:
+
+```ruby
+mycompany_customers({
+ bob: {
+ homedir: '/home/bob',
+ webdir: '/home/bob/web',
+ },
+}
+)
+```
+
+If there are many customer records in an environment, a simple recipe
+can be used to loop over every customer, like this:
+
+```ruby
+all_customers do |name, info|
+ directory info[:webdir] do
+ owner name
+ group name
+ action :create
+ end
+end
+```
+
+A simple library could be created that extends `Chef::Recipe::`, like
+this:
+
+```ruby
+class Chef
+ class Recipe
+ def all_customers(&block)
+ node["mycompany_customers"].each do |name, info|
+ block.call(name, info)
+ end
+ end
+ end
+end
+```
diff --git a/content/cookbooks/recipes/_index.md b/content/cookbooks/recipes/_index.md
new file mode 100644
index 0000000..57e5b76
--- /dev/null
+++ b/content/cookbooks/recipes/_index.md
@@ -0,0 +1,547 @@
++++
+title = "About Recipes"
+draft = false
+
+[menu]
+ [menu.cookbooks]
+ title = "About Recipes"
+ identifier = "cookbooks/recipes/recipes.md About Recipes"
+ parent = "cookbooks/recipes"
+ weight = 10
++++
+
+{{< readfile file="content/reusable/md/cookbooks_recipe.md" >}}
+
+## YAML and JSON recipes
+
+{{< readfile file = "content/reusable/md/recipes_yaml_json_overview.md" >}}
+
+See the [YAML and JSON recipe documentation]({{< relref "recipes_json_yaml" >}}) for more information.
+
+## Recipe Attributes
+
+{{< readfile file="content/reusable/md/cookbooks_attribute.md" >}}
+
+{{< note >}}
+
+{{< readfile file="content/reusable/md/notes_see_attributes_overview.md" >}}
+
+{{< /note >}}
+
+## Environment Variables
+
+In UNIX, a process environment is a set of key-value pairs made
+available to a process. Programs expect their environment to contain
+information required for the program to run. The details of how these
+key-value pairs are accessed depends on the API of the language being
+used.
+
+If processes is started by using the **execute** or **script** resources
+(or any of the resources based on those two resources, such as
+**bash**), use the `environment` attribute to alter the environment that
+will be passed to the process.
+
+```bash
+bash 'env_test' do
+ code <<-EOF
+ echo $FOO
+EOF
+ environment ({ 'FOO' => 'bar' })
+end
+```
+
+The only environment being altered is the one being passed to the child
+process that's started by the **bash** resource. This won't affect
+the Chef Infra Client environment or any child processes.
+
+## Work with Recipes
+
+The following sections show approaches to working with recipes.
+
+### Use Data Bags
+
+{{< readfile file="content/reusable/md/data_bag.md" >}}
+
+The contents of a data bag can be loaded into a recipe. For example, a
+data bag named `apps` and a data bag item named `my_app`:
+
+```json
+{
+ "id": "my_app",
+ "repository": "git://github.com/company/my_app.git"
+}
+```
+
+can be accessed in a recipe, like this:
+
+```ruby
+my_bag = data_bag_item('apps', 'my_app')
+```
+
+The data bag item's keys and values can be accessed with a Hash:
+
+```ruby
+my_bag['repository'] #=> 'git://github.com/company/my_app.git'
+```
+
+#### Secret Keys
+
+{{< readfile file="content/reusable/md/data_bag_encryption_secret_key.md" >}}
+
+#### Store Keys on Nodes
+
+An encryption key can also be stored in an alternate file on the nodes
+that need it and specify the path location to the file inside an
+attribute; however, `EncryptedDataBagItem.load` expects to see the
+actual secret as the third argument, rather than a path to the secret
+file. In this case, you can use `EncryptedDataBagItem.load_secret` to
+slurp the secret file contents and then pass them:
+
+```ruby
+# inside your attribute file:
+# default[:mysql][:secretpath] = 'C:\\chef\\any_secret_filename'
+#
+# inside your recipe:
+# look for secret in file pointed to by mysql attribute :secretpath
+mysql_secret = Chef::EncryptedDataBagItem.load_secret('#{node['mysql']['secretpath']}')
+mysql_creds = Chef::EncryptedDataBagItem.load('passwords', 'mysql', mysql_secret)
+mysql_creds['pass'] # will be decrypted
+```
+
+### Assign Dependencies
+
+If a cookbook has a dependency on a recipe that's located in another
+cookbook, that dependency must be declared in the metadata.rb file for
+that cookbook using the `depends` keyword.
+
+{{< note >}}
+
+Declaring cookbook dependencies isn't required with chef-solo.
+
+{{< /note >}}
+
+For example, if the following recipe is included in a cookbook named
+`my_app`:
+
+```ruby
+include_recipe 'apache2::mod_ssl'
+```
+
+Then the metadata.rb file for that cookbook would have:
+
+```ruby
+depends 'apache2'
+```
+
+### Include Recipes
+
+{{< readfile file="content/reusable/md/cookbooks_recipe_include_in_recipe.md" >}}
+
+### Reload Attributes
+
+Attributes sometimes depend on actions taken from within recipes, so it
+may be necessary to reload a given attribute from within a recipe. For
+example:
+
+```ruby
+ruby_block 'some_code' do
+ block do
+ node.from_file(run_context.resolve_attribute('COOKBOOK_NAME', 'ATTR_FILE'))
+ end
+ action :nothing
+end
+```
+
+### Use Ruby
+
+Anything that can be done with Ruby can be used within a recipe, such as
+expressions (if, unless, etc.), case statements, loop statements,
+arrays, hashes, and variables. In Ruby, the conditionals `nil` and
+`false` are false; every other conditional is `true`.
+
+#### Assign a value
+
+A variable uses an equals sign (`=`) to assign a value.
+
+To assign a value to a variable:
+
+```ruby
+package_name = 'apache2'
+```
+
+#### Use Case Statement
+
+A case statement can be used to compare an expression, and then execute
+the code that matches.
+
+To select a package name based on platform:
+
+```ruby
+package 'apache2' do
+ case node['platform']
+ when 'centos', 'redhat', 'fedora', 'suse'
+ package_name 'httpd'
+ when 'debian', 'ubuntu'
+ package_name 'apache2'
+ when 'arch'
+ package_name 'apache'
+ end
+ action :install
+end
+```
+
+#### Check Conditions
+
+An if expression can be used to check for conditions (true or false).
+
+To check for condition only for Debian and Ubuntu platforms:
+
+```ruby
+if platform?('debian', 'ubuntu')
+ # do something if node['platform'] is debian or ubuntu
+else
+ # do other stuff
+end
+```
+
+#### Execute Conditions
+
+An unless expression can be used to execute code when a condition
+returns a false value (effectively, an unless expression is the opposite
+of an if statement).
+
+To use an expression to execute when a condition returns a false value:
+
+```ruby
+unless node['platform_version'] == '5.0'
+ # do stuff on everything but 5.0
+end
+```
+
+#### Loop over Array
+
+A loop statement is used to execute a block of code one (or more) times.
+A loop statement is created when `.each` is added to an expression that
+defines an array or a hash. An array is an integer-indexed collection of
+objects. Each element in an array can be associated with and referred to
+by an index.
+
+To loop over an array of package names by platform:
+
+```ruby
+['apache2', 'apache2-mpm'].each do |p|
+ package p
+end
+```
+
+#### Loop over Hash
+
+A hash is a collection of key-value pairs. Indexing for a hash is done
+using arbitrary keys of any object (as opposed to the indexing done by
+an array). The syntax for a hash is: `key => "value"`.
+
+To loop over a hash of gem package names:
+
+```ruby
+{ 'fog' => '0.6.0', 'highline' => '1.6.0' }.each do |g, v|
+ gem_package g do
+ version v
+ end
+end
+```
+
+### Apply to Run-lists
+
+A recipe must be assigned to a run-list using the appropriate name, as
+defined by the cookbook directory and namespace. For example, a cookbook
+directory has the following structure:
+
+```text
+cookbooks/
+ apache2/
+ recipes/
+ default.rb
+ mod_ssl.rb
+```
+
+There are two recipes: a default recipe (that has the same name as the
+cookbook) and a recipe named `mod_ssl`. The syntax that applies a recipe
+to a run-list is similar to:
+
+```ruby
+{
+ 'run_list': [
+ 'recipe[cookbook_name::default_recipe]',
+ 'recipe[cookbook_name::recipe_name]'
+ ]
+}
+```
+
+where `::default_recipe` is implied (and doesn't need to be specified).
+On a node, these recipes can be assigned to a node's run-list similar
+to:
+
+```ruby
+{
+ 'run_list': [
+ 'recipe[apache2]',
+ 'recipe[apache2::mod_ssl]'
+ ]
+}
+```
+
+#### Chef Infra Server
+
+Use knife to add a recipe to the run-list for a node. For example:
+
+```bash
+knife node run list add NODENAME "recipe[apache2]"
+```
+
+More than one recipe can be added:
+
+```bash
+% knife node run list add NODENAME "recipe[apache2],recipe[mysql],role[ssh]"
+```
+
+which creates a run-list similar to:
+
+```ruby
+run_list:
+ recipe[apache2]
+ recipe[mysql]
+ role[ssh]
+```
+
+#### chef-solo
+
+Use a JSON file to pass run-list details to chef-solo as long as the
+cookbook in which the recipe is located is available to the system on
+which chef-solo is running. For example, a file named `dna.json`
+contains the following details:
+
+```json
+{
+ "run_list": ["recipe[apache2]"]
+}
+```
+
+To add the run-list to the node, enter the following:
+
+```bash
+sudo chef-solo -j /etc/chef/dna.json
+```
+
+### Use Search Results
+
+{{< readfile file="content/reusable/md/search.md" >}}
+
+The results of a search query can be loaded into a recipe. For example,
+a simple search query (in a recipe) might look like this:
+
+```ruby
+search(:node, 'attribute:value')
+```
+
+A search query can be assigned to variables and then used elsewhere in a
+recipe. For example, to search for all nodes that have a role assignment
+named `webserver`, and then render a template which includes those role
+assignments:
+
+```ruby
+webservers = search(:node, 'role:webserver')
+
+template '/tmp/list_of_webservers' do
+ source 'list_of_webservers.erb'
+ variables(webservers: webservers)
+end
+```
+
+### Use Tags
+
+{{< readfile file="content/reusable/md/chef_tags.md" >}}
+
+{{< readfile file="content/reusable/md/cookbooks_recipe_tags.md" >}}
+
+### End Chef Infra Client Run
+
+Sometimes it may be necessary to stop processing a recipe and/or stop
+processing the entire Chef Infra Client run. There are a few ways to do
+this:
+
+- Use the `return` keyword to stop processing a recipe based on a
+ condition, but continue processing a Chef Infra Client run
+- Use the `raise` keyword to stop a Chef Infra Client run by
+ triggering an unhandled exception
+- Use a `rescue` block in Ruby code
+- Use an [exception handler](/features/handlers/)
+
+The following sections show various approaches to ending a Chef Infra
+Client run.
+
+#### return Keyword
+
+The `return` keyword can be used to stop processing a recipe based on a
+condition, but continue processing a Chef Infra Client run. For example:
+
+```ruby
+file '/tmp/name_of_file' do
+ action :create
+end
+
+return if platform?('windows')
+
+package 'name_of_package' do
+ action :install
+end
+```
+
+where `platform?('windows')` is the condition set on the `return`
+keyword. When the condition is met, stop processing the recipe. This
+approach is useful when there is no need to continue processing, such as
+when a package can't be installed. In this situation, it's OK for a
+recipe to stop processing.
+
+#### raise Keyword
+
+In certain situations it may be useful to stop a Chef Infra Client run
+entirely by using an unhandled exception. The `raise` keyword can be used
+to stop a Chef Infra Client run in both the compile and execute phases.
+
+{{< note >}}
+
+You may also see code that uses the `fail` keyword, which behaves the same
+but is discouraged and will result in Cookstyle warnings.
+
+{{< /note >}}
+
+Use these keywords in a recipe---but outside of any resource blocks---to
+trigger an unhandled exception during the compile phase. For example:
+
+```ruby
+file '/tmp/name_of_file' do
+ action :create
+end
+
+raise "message" if platform?('windows')
+
+package 'name_of_package' do
+ action :install
+end
+```
+
+where `platform?('windows')` is the condition that will trigger the
+unhandled exception.
+
+Use these keywords in the **ruby_block** resource to trigger an
+unhandled exception during the execute phase. For example:
+
+```ruby
+ruby_block "name" do
+ block do
+ # Ruby code with a condition, for example if ::File.exist?(::File.join(path, "/tmp"))
+ raise "message" # for example "Ordering issue with file path, expected foo"
+ end
+end
+```
+
+Use these keywords in a class. For example:
+
+```ruby
+class CustomError < StandardError; end
+```
+
+and then later on:
+
+```ruby
+def custom_error
+ raise CustomError, "error message"
+end
+```
+
+or:
+
+```ruby
+def custom_error
+ raise CustomError, "error message"
+end
+```
+
+#### Rescue Blocks
+
+Since recipes are written in Ruby, they can be written to attempt to
+handle error conditions using the `rescue` block.
+
+For example:
+
+```ruby
+begin
+ dater = data_bag_item(:basket, 'flowers')
+rescue Net::HTTPClientException
+ # maybe some retry code here?
+ raise 'message_to_be_raised'
+end
+```
+
+where `data_bag_item` makes an HTTP request to Chef Infra Server to
+get a data bag item named `flowers`. If there is a problem, the request
+will return a `Net::HTTPClientException`. The `rescue` block can be used
+to try to retry or otherwise handle the situation. If the `rescue` block
+is unable to handle the situation, then the `raise` keyword is used to
+specify the message to be raised.
+
+### node.run_state
+
+Use `node.run_state` to stash transient data during a Chef Infra Client
+run. This data may be passed between resources, and then evaluated
+during the execution phase. `run_state` is an empty Hash that's always
+discarded at the end of a Chef Infra Client run.
+
+For example, the following recipe will install the Apache web server,
+randomly choose PHP or Perl as the scripting language, and then install
+that scripting language:
+
+```ruby
+package 'httpd' do
+ action :install
+end
+
+ruby_block 'randomly_choose_language' do
+ block do
+ if Random.rand > 0.5
+ node.run_state['scripting_language'] = 'php'
+ else
+ node.run_state['scripting_language'] = 'perl'
+ end
+ end
+end
+
+package 'scripting_language' do
+ package_name lazy { node.run_state['scripting_language'] }
+ action :install
+end
+```
+
+where:
+
+- The **ruby_block** resource declares a `block` of Ruby code that's
+ run during the execution phase of a Chef Infra Client run
+- The `if` statement randomly chooses PHP or Perl, saving the choice
+ to `node.run_state['scripting_language']`
+- When the **package** resource has to install the package for the
+ scripting language, it looks up the scripting language and uses the
+ one defined in `node.run_state['scripting_language']`
+- `lazy {}` ensures that the **package** resource evaluates this
+ during the execution phase of a Chef Infra Client run (as opposed to
+ during the compile phase)
+
+When this recipe runs, Chef Infra Client will print something like the
+following:
+
+```bash
+* ruby_block[randomly_choose_language] action run
+ - execute the ruby block randomly_choose_language
+
+* package[scripting_language] action install
+ - install version 5.3.3-27.el6_5 of package php
+```
diff --git a/content/cookbooks/recipes/debug.md b/content/cookbooks/recipes/debug.md
new file mode 100644
index 0000000..03cd71f
--- /dev/null
+++ b/content/cookbooks/recipes/debug.md
@@ -0,0 +1,350 @@
++++
+title = "Debug Recipes, Chef Infra Client Runs"
+draft = false
+
+[menu]
+ [menu.cookbooks]
+ title = "Debug Recipes, Client Runs"
+ identifier = "cookbooks/recipes/debug.md Debug Recipes, Client Runs"
+ parent = "cookbooks/recipes"
+ weight = 20
++++
+
+Elements of good approaches to building cookbooks and recipes that are
+reliable include:
+
+* A consistent syntax pattern when constructing recipes
+* Using the same patterns in Ruby
+* Using resources included in Chef Infra Client or community cookbooks before creating custom ones
+
+Ideally, the best way to debug a recipe is to not have to debug it in the first place. That said, the following sections discuss various approaches to debugging recipes and failed Chef Infra Client runs.
+
+## Basic
+
+Some simple ways to identify common issues that can trigger recipe and/or Chef Infra Client run failures include:
+
+* Using an empty run-list
+* Using verbose logging with knife
+* Using logging with Chef Infra Client
+* Using the **log** resource in a recipe to define custom logging
+
+### Empty Run-lists
+
+{{< readfile file="content/reusable/md/node_run_list_empty.md" >}}
+
+### Knife
+
+Use the verbose logging that's built into knife:
+
+`-V`, `--verbose`
+
+: Set for more verbose outputs. Use `-VV` for much more verbose outputs. Use `-VVV` for maximum verbosity, which may provide more information than is actually helpful.
+
+{{< note >}}
+
+Plugins don't always support verbose logging.
+
+{{< /note >}}
+
+### Chef Infra Client
+
+Use the verbose logging that's built into Chef Infra Client:
+
+`-l LEVEL`, `--log_level LEVEL`
+
+: The level of logging to be stored in a log file. Possible levels: `auto` (default), `debug`, `error`, `fatal`, `info`, `trace`, or `warn`. Default value: `warn` (when a terminal is available) or `info` (when a terminal isn't available).
+
+`-L LOGLOCATION`, `--logfile c`
+
+: The location of the log file. This is recommended when starting any executable as a daemon. Default value: `STDOUT`.
+
+### log Resource
+
+Use the **log** resource to create log entries. The **log** resource
+behaves like any other resource: built into the resource collection
+during the compile phase, and then run during the execution phase. (To
+create a log entry that isn't built into the resource collection, use
+`Chef::Log` instead of the **log** resource.)
+
+{{< note >}}
+
+By default, every log resource that executes will count as an updated
+resource in the updated resource count at the end of a Chef run. You can
+disable this behavior by adding `count_log_resource_updates false` to
+your Chef `client.rb` configuration file.
+
+{{< /note >}}
+
+New in 12.0, `-o RUN_LIST_ITEM`. Changed in 12.0 `-f` no longer allows unforked intervals, `-i SECONDS` is applied before a Chef Infra Client run.
+
+#### Syntax
+
+{{< readfile file="content/reusable/md/resource_log_syntax.md" >}}
+
+#### Actions
+
+The log resource has the following actions:
+
+`:nothing`
+
+: {{< readfile file="content/reusable/md/resources_common_actions_nothing.md" >}}
+
+`:write`
+
+: Default. Write to log.
+
+#### Properties
+
+{{< readfile file="content/reusable/md/resource_log_properties.md" >}}
+
+#### Examples
+
+The following examples demonstrate various approaches for using
+resources in recipes:
+
+##### Specify a Log Entry
+
+```ruby
+log 'a string to log'
+```
+
+##### Set debug logging level
+
+{{< readfile file="content/reusable/md/resource_log_set_debug.md" >}}
+
+##### Create log entry when the contents of a data bag are used
+
+{{< readfile file="content/reusable/md/resource_log_set_debug.md" >}}
+
+##### Add a message to a log file
+
+```ruby
+log 'message' do
+ message 'This is the message that will be added to the log.'
+ level :info
+end
+```
+
+## Advanced
+
+Some more complex ways to debug issues with a Chef Infra Client run
+include:
+
+* Using the **chef_handler** resource
+* Using the chef-shell and the **breakpoint** resource to add breakpoints to recipes, and to then step through the recipes using the breakpoints
+* Using the `debug_value` method from chef-shell to identify the locations from which attribute values are being set
+* Using the `ignore_failure` method in a recipe to force Chef Infra Client to move past an error to see what else is going on in the recipe, outside of a known failure
+* Using chef-solo to run targeted Chef Infra Client runs for specific scenarios
+
+### chef_handler
+
+{{< readfile file="content/reusable/md/handler.md" >}}
+
+{{< readfile file="content/reusable/md/handler_types.md" >}}
+
+Read more [about exception, report, and start handlers](/features/handlers/).
+
+### chef-shell
+
+{{< readfile file="content/reusable/md/chef_shell_summary.md" >}}
+
+{{< readfile file="content/reusable/md/chef_shell_modes.md" >}}
+
+#### Configure
+
+{{< readfile file="content/reusable/md/chef_shell_config.md" >}}
+
+#### chef-shell.rb
+
+{{< readfile file="content/reusable/md/chef_shell_config_rb.md" >}}
+
+#### Run as a Chef Infra Client
+
+{{< readfile file="content/reusable/md/chef_shell_run_as_chef_client.md" >}}
+
+#### Manage
+
+{{< readfile file="content/reusable/md/chef_shell_manage.md" >}}
+
+### breakpoint Resource
+
+{{< readfile file="content/reusable/md/chef_shell_breakpoints.md" >}}
+
+Use the **breakpoint** resource to add breakpoints to recipes. Run the
+chef-shell in Chef Infra Client mode, and then use those breakpoints to
+debug recipes. Breakpoints are ignored by Chef Infra Client during an
+actual Chef Infra Client run. That said, breakpoints are typically used
+to debug recipes only when running them in a non-production environment,
+after which they're removed from those recipes before the parent
+cookbook is uploaded to Chef Infra Server.
+
+#### Syntax
+
+A **breakpoint** resource block creates a breakpoint in a recipe:
+
+```ruby
+breakpoint 'name' do
+ action :break
+end
+```
+
+where
+
+`:break` will tell Chef Infra Client to stop running a recipe; can
+only be used when Chef Infra Client is being run in chef-shell mode
+
+#### Actions
+
+The breakpoint resource has the following actions:
+
+`:break`
+
+: Use to add a breakpoint to a recipe.
+
+`:nothing`
+
+: {{< readfile file="content/reusable/md/resources_common_actions_nothing.md" >}}
+
+#### Attributes
+
+This resource doesn't have any properties.
+
+#### Examples
+
+The following examples demonstrate various approaches for using resources in recipes:
+
+##### A recipe without a breakpoint
+
+```ruby
+yum_key node['yum']['elrepo']['key'] do
+ url node['yum']['elrepo']['key_url']
+ action :add
+end
+
+yum_repository 'elrepo' do
+ description 'ELRepo.org Community Enterprise Linux Extras Repository'
+ key node['yum']['elrepo']['key']
+ mirrorlist node['yum']['elrepo']['url']
+ includepkgs node['yum']['elrepo']['includepkgs']
+ exclude node['yum']['elrepo']['exclude']
+ action :create
+end
+```
+
+##### The same recipe with breakpoints
+
+```ruby
+breakpoint "before yum_key node['yum']['repo_name']['key']" do
+ action :break
+end
+
+yum_key node['yum']['repo_name']['key'] do
+ url node['yum']['repo_name']['key_url']
+ action :add
+end
+
+breakpoint "after yum_key node['yum']['repo_name']['key']" do
+ action :break
+end
+
+breakpoint "before yum_repository 'repo_name'" do
+ action :break
+end
+
+yum_repository 'repo_name' do
+ description 'description'
+ key node['yum']['repo_name']['key']
+ mirrorlist node['yum']['repo_name']['url']
+ includepkgs node['yum']['repo_name']['includepkgs']
+ exclude node['yum']['repo_name']['exclude']
+ action :create
+end
+
+breakpoint "after yum_repository 'repo_name'" do
+ action :break
+end
+```
+
+where the name of each breakpoint is an arbitrary string. In the
+previous examples, the names are used to indicate if the breakpoint is
+before or after a resource, and then also to specify which resource.
+
+### Step Through Run-list
+
+{{< readfile file="content/reusable/md/chef_shell_step_through_run_list.md" >}}
+
+### Debug Existing Recipe
+
+{{< readfile file="content/reusable/md/chef_shell_debug_existing_recipe.md" >}}
+
+### Advanced Debugging
+
+{{< readfile file="content/reusable/md/chef_shell_advanced_debug.md" >}}
+
+### debug_value
+
+Use the `debug_value` method to discover the location within the attribute precedence hierarchy from which a particular attribute (or sub-attribute) is set. This method is available when running chef-shell in Chef Infra Client mode:
+
+```bash
+chef-shell -z
+```
+
+For example, the following attributes exist in a cookbook. Some are defined in a role file:
+
+```ruby
+default_attributes 'test' => { 'source' => 'role default' }
+override_attributes 'test' => { 'source' => 'role override' }
+```
+
+And others are defined in an attributes file:
+
+```ruby
+default[:test][:source] = 'attributes default'
+normal[:test][:source] = 'attributes normal'
+override[:test][:source] = 'attributes override'
+```
+
+To debug the location in which the value of `node[:test][:source]` is set, use chef-shell and run a command similar to:
+
+```ruby
+pp node.debug_value('test', 'source')
+```
+
+This will pretty-print return all of the attributes and sub-attributes as an array of arrays; `:not_present` is returned for any attribute without a value:
+
+```bash
+[['set_unless_enabled?', false],
+ ['default', 'attributes default'],
+ ['env_default', :not_present],
+ ['role_default', 'role default'],
+ ['force_default', :not_present],
+ ['normal', 'attributes normal'],
+ ['override', 'attributes override'],
+ ['role_override', 'role override'],
+ ['env_override', :not_present],
+ ['force_override', :not_present],
+ ['automatic', :not_present]]
+```
+
+where
+
+* `set_unless_enabled` indicates if the attribute collection is in `set_unless` mode; this typically returns `false`
+* Each attribute type is listed in order of precedence
+* Each attribute value shown is the value that's set for that precedence level
+* `:not_present` is shown for any attribute precedence level that has no attributes
+
+### ignore_failure method
+
+All resources share a set of common actions, attributes, and other properties. Use the following attribute in a resource to help identify where an issue within a recipe may be located:
+
+| Attribute | Description |
+|----------------|---------------------------------------------------------------------------------------|
+| ignore_failure | Continue running a recipe if a resource fails for any reason. Default value: `false`. |
+
+### chef-solo
+
+See [chef-solo (executable)](/features/chef_solo/ctl_chef_solo/) for complete CTL documentation.
+
+{{< readfile file="content/reusable/md/chef_solo_summary.md" >}}
+
+See [chef-solo (executable)](/features/chef_solo/ctl_chef_solo/) for complete CTL documentation.
diff --git a/content/cookbooks/recipes/recipes_json_yaml.md b/content/cookbooks/recipes/recipes_json_yaml.md
new file mode 100644
index 0000000..da18ca2
--- /dev/null
+++ b/content/cookbooks/recipes/recipes_json_yaml.md
@@ -0,0 +1,499 @@
++++
+title = "Chef Infra JSON and YAML recipes"
+draft = false
+gh_repo = "chef-web-docs"
+
+[menu]
+ [menu.infra]
+ title = "JSON/YAML recipes"
+ identifier = "chef_infra/cookbook_reference/recipes/YAML recipes"
+ parent = "chef_infra/cookbook_reference/recipes"
+ weight = 20
++++
+
+{{< readfile file = "content/reusable/md/recipes_yaml_json_overview.md" >}}
+
+For information about Ruby recipes, see the [Ruby recipe documentation]({{< relref "recipes" >}}).
+
+## Support
+
+We introduced YAML recipes in Chef Infra Client 16.0. We added support for YAML recipes with the `.yml` file extension in Infra Client 17.2.29. We added support for JSON recipes in Chef Infra Client 18.8.
+
+## Create a JSON or YAML recipe
+
+To create a JSON or YAML recipe, follow these steps:
+
+1. Create a JSON or YAML file for your recipe in the same locations as Ruby recipes:
+
+ - Standard recipe location:
+
+ - `cookbooks/cookbook_name/recipes/default.yml`
+ - `cookbooks/cookbook_name/recipes/default.yaml`
+ - `cookbooks/cookbook_name/recipes/default.json`
+
+ - Named recipes:
+
+ - `cookbooks/cookbook_name/recipes/web.yml`
+ - `cookbooks/cookbook_name/recipes/database.yaml`
+ - `cookbooks/cookbook_name/recipes/app.json`
+
+ - Root-level recipe alias (acts as the default recipe):
+
+ - `cookbooks/cookbook_name/recipe.yml`
+ - `cookbooks/cookbook_name/recipe.yaml`
+ - `cookbooks/cookbook_name/recipe.json`
+
+ {{< note >}}
+
+ Creating more than one recipe with the same filename but different file extensions isn't supported. For example, `default.yaml` and `default.yml`.
+
+ {{< /note >}}
+
+1. Define your recipe with the top-level `resources` key containing an array of items where each item has the following:
+
+ - `type`: The Chef resource type (string)
+ - `name`: The resource name/identifier (string)
+ - resource-specific actions and properties as key-value pairs
+
+ For example:
+
+ {{< foundation_tabs tabs-id="create-json-yaml-recipe-example" >}}
+ {{< foundation_tab active="true" panel-link="create-yaml-recipe-example" tab-text="YAML">}}
+ {{< foundation_tab panel-link="create-json-recipe-example" tab-text="JSON" >}}
+ {{< /foundation_tabs >}}
+
+ {{< foundation_tabs_panels tabs-id="create-json-yaml-recipe-example" >}}
+ {{< foundation_tabs_panel active="true" panel-id="create-yaml-recipe-example" >}}
+
+ ```yaml
+ resources:
+ - type: "package"
+ name: "nginx"
+ action: "install"
+ version: "1.18.0"
+ - type: "service"
+ name: "nginx"
+ action: ["enable", "start"]
+ ```
+
+ {{< /foundation_tabs_panel >}}
+
+ {{< foundation_tabs_panel panel-id="create-json-recipe-example" >}}
+
+ ```json
+ {
+ "resources": [
+ {
+ "type": "package",
+ "name": "nginx",
+ "action": "install",
+ "version": "1.18.0"
+ },
+ {
+ "type": "service",
+ "name": "nginx",
+ "action": [
+ "enable",
+ "start"
+ ]
+ }
+ ]
+ }
+ ```
+
+ {{< /foundation_tabs_panel >}}
+ {{< /foundation_tabs_panels >}}
+
+ In this example:
+
+ - the [`package` resource]({{< relref "/resources/bundled/package/" >}}) uses the `install` action and the `version` property to install Nginx 1.18.0.
+ - the [`service` resource]({{< relref "/resources/bundled/service/" >}}) uses the `enable` and `start` actions to enable and start Nginx.
+
+## Examples
+
+### Basic file management
+
+Use the [`directory` resource]({{< relref "/resources/bundled/directory">}}) to create the `/opt/app_name` directory and apply owner and group permissions to the directory. Use the [`file` resource]({{< relref "/resources/bundled/">}}) to create the `/opt/app_name/config.txt` file, add text to the file, and apply file owner and group permissions to the file.
+
+{{< foundation_tabs tabs-id="basic-file-management-json-yaml-recipe-example" >}}
+ {{< foundation_tab active="true" panel-link="basic-file-management-yaml-recipe-example" tab-text="YAML">}}
+ {{< foundation_tab panel-link="basic-file-management-json-recipe-example" tab-text="JSON" >}}
+{{< /foundation_tabs >}}
+
+{{< foundation_tabs_panels tabs-id="basic-file-management-json-yaml-recipe-example" >}}
+{{< foundation_tabs_panel active="true" panel-id="basic-file-management-yaml-recipe-example" >}}
+
+```yaml
+---
+resources:
+ - type: "directory"
+ name: "/opt/app_name"
+ owner: "app_name"
+ group: "app_name"
+ mode: "0755"
+ recursive: true
+
+ - type: "file"
+ name: "/opt/app_name/config.txt"
+ content: "This is a configuration file"
+ owner: "app_name"
+ group: "app_name"
+ mode: "0644"
+```
+
+{{< /foundation_tabs_panel >}}
+
+{{< foundation_tabs_panel panel-id="basic-file-management-json-recipe-example" >}}
+
+```json
+{
+ "resources": [
+ {
+ "type": "directory",
+ "name": "/opt/app_name",
+ "owner": "app_name",
+ "group": "app_name",
+ "mode": "0755",
+ "recursive": true
+ },
+ {
+ "type": "file",
+ "name": "/opt/app_name/config.txt",
+ "content": "This is a configuration file",
+ "owner": "app_name",
+ "group": "app_name",
+ "mode": "0644"
+ }
+ ]
+}
+```
+
+{{< /foundation_tabs_panel >}}
+{{< /foundation_tabs_panels >}}
+
+### Package and service management
+
+Use the [`package` resource]({{< relref "/resources/bundled/package">}}) to install Nginx and curl. Then use the [`service` resource]({{< relref "/resources/bundled/service">}}) to enable and start Nginx.
+
+{{< foundation_tabs tabs-id="package-service-management-json-yaml-recipe-example" >}}
+ {{< foundation_tab active="true" panel-link="package-service-management-yaml-recipe-example" tab-text="YAML">}}
+ {{< foundation_tab panel-link="package-service-management-json-recipe-example" tab-text="JSON" >}}
+{{< /foundation_tabs >}}
+
+{{< foundation_tabs_panels tabs-id="package-service-management-json-yaml-recipe-example" >}}
+{{< foundation_tabs_panel active="true" panel-id="package-service-management-yaml-recipe-example" >}}
+
+```yaml
+---
+resources:
+ - type: "package"
+ name: "nginx"
+ action: "install"
+
+ - type: "package"
+ name: "curl"
+ action: "install"
+
+ - type: "service"
+ name: "nginx"
+ action: ["enable", "start"]
+```
+
+{{< /foundation_tabs_panel >}}
+
+{{< foundation_tabs_panel panel-id="package-service-management-json-recipe-example" >}}
+
+```json
+{
+ "resources": [
+ {
+ "type": "package",
+ "name": "nginx",
+ "action": "install"
+ },
+ {
+ "type": "package",
+ "name": "curl",
+ "action": "install"
+ },
+ {
+ "type": "service",
+ "name": "nginx",
+ "action": [
+ "enable",
+ "start"
+ ]
+ }
+ ]
+}
+```
+
+{{< /foundation_tabs_panel >}}
+{{< /foundation_tabs_panels >}}
+
+### User management
+
+Use the [`group` resource]({{< relref "/resources/bundled/group">}}) to create a group called "developers" and the [`user` resource]({{< relref "/resources/bundled/">}}) to create a user, give them properties, and assign them to the developers group.
+
+{{< foundation_tabs tabs-id="user-management-json-yaml-recipe-example" >}}
+ {{< foundation_tab active="true" panel-link="user-management-yaml-recipe-example" tab-text="YAML">}}
+ {{< foundation_tab panel-link="user-management-json-recipe-example" tab-text="JSON" >}}
+{{< /foundation_tabs >}}
+
+{{< foundation_tabs_panels tabs-id="user-management-json-yaml-recipe-example" >}}
+{{< foundation_tabs_panel active="true" panel-id="user-management-yaml-recipe-example" >}}
+
+```yaml
+---
+resources:
+ - type: "group"
+ name: "developers"
+ gid: 3000
+
+ - type: "user"
+ name: "alice"
+ uid: 2001
+ gid: 3000
+ home: "/home/alice"
+ shell: "/bin/bash"
+ action: "create"
+```
+
+{{< /foundation_tabs_panel >}}
+
+{{< foundation_tabs_panel panel-id="user-management-json-recipe-example" >}}
+
+```json
+{
+ "resources": [
+ {
+ "type": "group",
+ "name": "developers",
+ "gid": 3000
+ },
+ {
+ "type": "user",
+ "name": "alice",
+ "uid": 2001,
+ "gid": 3000,
+ "home": "/home/alice",
+ "shell": "/bin/bash",
+ "action": "create"
+ }
+ ]
+}
+```
+
+{{< /foundation_tabs_panel >}}
+{{< /foundation_tabs_panels >}}
+
+### Template with static variables
+
+Use the [`template` resource]({{< relref "/resources/bundled/template">}}) create the `/etc/app_name/config.yml` file using the `config.yml.erb` template.
+
+{{< foundation_tabs tabs-id="template-with-static-variables-json-yaml-recipe-example" >}}
+ {{< foundation_tab active="true" panel-link="template-with-static-variables-yaml-recipe-example" tab-text="YAML">}}
+ {{< foundation_tab panel-link="template-with-static-variables-json-recipe-example" tab-text="JSON" >}}
+{{< /foundation_tabs >}}
+
+{{< foundation_tabs_panels tabs-id="template-with-static-variables-json-yaml-recipe-example" >}}
+{{< foundation_tabs_panel active="true" panel-id="template-with-static-variables-yaml-recipe-example" >}}
+
+```yaml
+---
+resources:
+ - type: "template"
+ name: "/etc/app_name/config.yml"
+ source: "config.yml.erb"
+ owner: "root"
+ group: "root"
+ mode: "0644"
+```
+
+{{< /foundation_tabs_panel >}}
+
+{{< foundation_tabs_panel panel-id="template-with-static-variables-json-recipe-example" >}}
+
+```json
+{
+ "resources": [
+ {
+ "type": "template",
+ "name": "/etc/app_name/config.yml",
+ "source": "config.yml.erb",
+ "owner": "root",
+ "group": "root",
+ "mode": "0644"
+ }
+ ]
+}
+```
+
+{{< /foundation_tabs_panel >}}
+{{< /foundation_tabs_panels >}}
+
+### Guards
+
+Some common resource functionality is also supported, as long as the value of a property can be expressed as one of the four primitive types (string, integer, boolean, array). That means it's possible to use [`only_if` or `not_if` guards]({{< relref "/resources/common_functionality/#guards" >}}) as long as they shell out to Bash or PowerShell and aren't passed a Ruby block.
+
+For example, this is supported:
+
+{{< foundation_tabs tabs-id="guards-json-yaml-recipe-example" >}}
+ {{< foundation_tab active="true" panel-link="guards-yaml-recipe-example" tab-text="YAML">}}
+ {{< foundation_tab panel-link="guards-json-recipe-example" tab-text="JSON" >}}
+{{< /foundation_tabs >}}
+
+{{< foundation_tabs_panels tabs-id="guards-json-yaml-recipe-example" >}}
+{{< foundation_tabs_panel active="true" panel-id="guards-yaml-recipe-example" >}}
+
+```yaml
+resources:
+- type: "directory"
+ name: "/var/www/html"
+ only_if: "which apache2"
+```
+
+{{< /foundation_tabs_panel >}}
+
+{{< foundation_tabs_panel panel-id="guards-json-recipe-example" >}}
+
+```json
+{
+ "resources": [
+ {
+ "type": "directory",
+ "name": "/var/www/html",
+ "only_if": "which apache2"
+ }
+ ]
+}
+```
+
+{{< /foundation_tabs_panel >}}
+{{< /foundation_tabs_panels >}}
+
+Ruby blocks aren't supported:
+
+```yaml
+# Can't be expressed in YAML - Ruby blocks not supported
+resources:
+- type: "directory"
+ name: "/var/www/html"
+ only_if: "{ ::File.exist?('/usr/sbin/apache2') }"
+```
+
+## Convert a YAML recipe to Ruby
+
+Use the `knife yaml convert` command to convert YAML recipes to Ruby:
+
+```shell
+knife yaml convert recipes/default.yml recipes/default.rb
+```
+
+Converting from Ruby to YAML or JSON isn't supported due to their limitations.
+
+## YAML and JSON recipe limitations
+
+Chef Infra YAML and JSON recipes have the following limitations.
+
+### No Ruby code blocks
+
+YAML and JSON recipes can't include Ruby code blocks, which limits their functionality compared to Ruby recipes:
+
+```ruby
+# Can't be expressed in YAML - Ruby blocks not supported
+template "/etc/nginx/nginx.conf" do
+ source "nginx.conf.erb"
+ variables({
+ worker_processes: node['cpu']['total']
+ })
+ notifies :restart, "service[nginx]", :delayed
+ only_if { node['platform'] == 'ubuntu' }
+end
+```
+
+### No conditional logic
+
+YAML and JSON recipes can't include conditional logic like `if`, `unless`, `only_if`, or `not_if` with Ruby expressions:
+
+```yaml
+# Can't include complex conditionals
+resources:
+ - type: "package"
+ name: "nginx"
+ # Can't do: only_if { node['platform'] == 'ubuntu' }
+```
+
+### No node attribute access
+
+YAML and JSON recipes can't directly access node attributes or perform Ruby evaluations:
+
+```yaml
+# Can't access node attributes dynamically
+resources:
+ - type: "user"
+ name: "webapp"
+ # Can't do: home "/home/#{node['webapp']['user']}"
+ home: "/home/webapp" # Must be static
+```
+
+### No resource notifications
+
+YAML and JSON recipes can't express complex resource relationships and notifications:
+
+```yaml
+# Can't express notifications between resources
+resources:
+ - type: "template"
+ name: "/etc/nginx/nginx.conf"
+ source: "nginx.conf.erb"
+ # Can't do: notifies :restart, "service[nginx]", :delayed
+```
+
+### No include or require functionality
+
+YAML and JSON recipes can't include other recipes or libraries:
+
+```yaml
+# Can't include other recipes
+# include_recipe "cookbook::other_recipe"
+```
+
+## Troubleshooting
+
+### Missing `resources` key
+
+Chef Infra Client returns this error if a recipe is missing the top-level `resources` hash.
+
+```text
+ArgumentError: YAML recipe 'recipes/default.yml' must contain a top-level 'resources' hash (YAML sequence), i.e. 'resources:'
+```
+
+### Single document limitation
+
+YAML recipes support only one YAML document in each file. Multiple documents separated by `---` aren't allowed:
+
+```yaml
+---
+resources:
+ - type: "file"
+ name: "/tmp/file1.txt"
+---
+resources:
+ - type: "file"
+ name: "/tmp/file2.txt"
+```
+
+Chef Infra Client returns the following error with multiple documents in one file:
+
+```text
+ArgumentError: YAML recipe 'recipes/default.yml' contains multiple documents, only one is supported
+```
+
+### Ambiguous file extensions
+
+Chef Infra Client returns this error if two recipes have the same filename with different file extensions. For example, `default.yaml` and `default.yml`.
+
+```text
+Chef::Exceptions::AmbiguousYAMLFile: Found both default.yml and default.yaml in cookbook, update the cookbook to remove one
+```
diff --git a/content/cookbooks/templates.md b/content/cookbooks/templates.md
new file mode 100644
index 0000000..ae2cea6
--- /dev/null
+++ b/content/cookbooks/templates.md
@@ -0,0 +1,90 @@
++++
+title = "About Templates"
+draft = false
+
+[menu]
+ [menu.cookbooks]
+ title = "Templates"
+ identifier = "cookbooks/templates.md Templates"
+ parent = "cookbooks"
+ weight = 100
++++
+
+{{< readfile file="content/reusable/md/template.md" >}}
+
+The `templates` directory doesn't exist by default in a cookbook.
+Generate the `templates` directory and a template file from the `chef-repo/cookbooks` directory with the command:
+
+```bash
+chef generate template PATH_TO_COOKBOOK TEMPLATE_NAME
+```
+
+For example, this command generates a `httpd` template in the `custom_web` cookbook:
+
+```bash
+chef generate template cookbooks/custom_web httpd
+```
+
+The `custom_web` cookbook directory with a template has the structure:
+
+```text
+. cookbooks
+├── README.md
+└── custom_web
+ ├── CHANGELOG.md
+ ├── LICENSE
+ ├── Policyfile.rb
+ ├── README.md
+ ├── chefignore
+ ├── compliance
+ │ ├── README.md
+ │ ├── inputs
+ │ ├── profiles
+ │ └── waivers
+ ├── kitchen.yml
+ ├── metadata.rb
+ ├── recipes
+ │ └── default.rb
+ ├── templates
+ │ └── httpd.erb
+ └── test
+ └── integration
+ └── default
+ └── default_test.rb
+```
+
+## Requirements
+
+{{< readfile file="content/reusable/md/template_requirements.md" >}}
+
+## Variables
+
+{{< readfile file="content/reusable/md/template_variables.md" >}}
+
+## File Specificity
+
+{{< readfile file="content/reusable/md/template_specificity.md" >}}
+
+{{< readfile file="content/reusable/md/template_specificity_pattern.md" >}}
+
+{{< readfile file="content/reusable/md/template_specificity_example.md" >}}
+
+## Host Notation
+
+{{< readfile file="content/reusable/md/template_host_notation.md" >}}
+
+## Transfer Frequency
+
+{{< readfile file="content/reusable/md/template_transfer_frequency.md" >}}
+
+## Partial Templates
+
+{{< readfile file="content/reusable/md/template_partials.md" >}}
+
+### variables Attribute
+
+{{< readfile file="content/reusable/md/template_partials_variables_attribute.md" >}}
+
+### render Method
+
+{{< readfile file="content/reusable/md/template_partials_render_method.md" >}}
diff --git a/content/extension_apis/_index.md b/content/extension_apis/_index.md
new file mode 100644
index 0000000..1f75574
--- /dev/null
+++ b/content/extension_apis/_index.md
@@ -0,0 +1,5 @@
++++
+title = "Extension APIs"
+
+list_pages = true
++++
\ No newline at end of file
diff --git a/content/extension_apis/community_plugins.md b/content/extension_apis/community_plugins.md
new file mode 100644
index 0000000..cf4112c
--- /dev/null
+++ b/content/extension_apis/community_plugins.md
@@ -0,0 +1,102 @@
++++
+title = "Community Plugins"
+draft = false
+
+[menu]
+ [menu.extension_apis]
+ title = "Community Plugins"
+ identifier = "extension_apis/ohai_plugins/Community Plugins"
+ parent = "extension_apis/ohai_plugins"
+ weight = 20
++++
+
+
+This page lists plugins for Ohai plugins and Chef Infra Client handlers
+that are developed and maintained by the Chef community.
+
+## Ohai
+
+{{< readfile file="content/reusable/md/ohai_summary.md" >}}
+
+The following Ohai plugins are available from the open source community:
+
+
+
+
+
+
+
+
+
+
+
+| dell.rb |
+Adds some useful Dell server information to Ohai. For example, service tag, express service code, storage info, or RAC info. To use this plugin, OMSA and SMBIOS applications need to be installed. |
+
+
+| ipmi.rb |
+Adds a MAC address and an IP address to Ohai, where available. |
+
+
+| kvm_extensions.rb |
+Adds extensions for virtualization attributes to provide additional host and guest information for KVM. |
+
+
+| ladvd.rb |
+Adds ladvd information to Ohai, when it exists. |
+
+
+| lxc_virtualization.rb |
+Adds extensions for virtualization attributes to provide host and guest information for Linux containers. |
+
+
+| network_addr.rb |
+Adds extensions for network attributes with additional ipaddrtype_iface attributes to make it semantically easier to retrieve addresses. |
+
+
+| network_ports.rb |
+Adds extensions for network attributes so that Ohai can detect to which interfaces TCP and UDP ports are bound. |
+
+
+| parse_host_plugin.rb |
+Adds the ability to parse a host name using three top-level attribute and five nested attributes. |
+
+
+| r.rb |
+Adds the ability to collect basic information about the R Project. |
+
+
+| sysctl.rb |
+Adds sysctl information to Ohai. |
+
+
+| vserver.rb |
+Adds extensions for virtualization attributes to allow a Linux virtual server host and guest information to be used by Ohai. |
+
+
+| wtf.rb |
+Adds the irreverent wtfismyip.com service so that Ohai can determine a machine's external IPv4 address and geographical location. |
+
+
+| xenserver.rb |
+Adds extensions for virtualization attributes to load up Citrix XenServer host and guest information. |
+
+
+| win32_software.rb |
+Adds the ability for Ohai to use Windows Management Instrumentation (WMI) to discover useful information about software that's installed on any node that's running Windows. |
+
+
+| win32_svc.rb |
+Adds the ability for Ohai to query using Windows Management Instrumentation (WMI) to get information about all services that are registered on a node that's running Windows. |
+
+
+
+
+## Handlers
+
+{{< readfile file="content/reusable/md/handler.md" >}}
+
+{{< readfile file="content/reusable/md/handler_community_handlers.md" >}}
diff --git a/content/extension_apis/custom_plugins.md b/content/extension_apis/custom_plugins.md
new file mode 100644
index 0000000..74edd37
--- /dev/null
+++ b/content/extension_apis/custom_plugins.md
@@ -0,0 +1,599 @@
++++
+title = "Writing Ohai Custom Plugins"
+draft = false
+
+[menu]
+ [menu.extension_apis]
+ title = "Custom Plugins"
+ identifier = "extension_apis/ohai_plugins/ohai_custom.md Custom Plugins"
+ parent = "extension_apis/ohai_plugins"
+ weight = 10
++++
+
+You can write custom Ohai plugins to collect additional configuration attributes with Ohai to provide to Chef Infra Client during runs.
+
+Ohai plugins are written in Ruby with a plugin DSL documented below. Being written in Ruby provides access to all Ruby's built-in functionality, as well as 3rd party gem functionality. Plugins can parse the output of any local command on the node, or they can fetch data from external APIs. Examples of plugins that users have written: - A plugin to gather node information including data center, rack, and rack position from an inventory server - A plugin to gather additional RAID array information from a controller utility - A plugin to gather hardware
+warranty information from a vendor API
+
+See [About Ohai](/features/ohai/) for information on Ohai configuration and usage.
+
+## Install Ohai Plugins
+
+Install custom Ohai plugins by creating an `ohai` directory in your cookbook and saving your plugin code to this location.
+
+To migrate custom Ohai plugins from the deprecated ohai cookbook:
+
+1. Create an `ohai` directory in your cookbook
+1. Move your plugin into the `ohai` directory
+1. Remove the outdated custom Ohai plugin installation code from your code
+
+Chef Infra Client will move the file into the correct location, load it, and return the data in the next configuration run. Chef Infra Client will provide other cookbooks that depend on the custom Ohai plugin with the correct data.
+
+## Syntax
+
+The syntax for an Ohai plugin is as follows:
+
+```ruby
+Ohai.plugin(:Name) do
+ provides 'attribute', 'attribute/subattribute'
+ depends 'attribute', 'attribute'
+
+ def shared_method
+ # some Ruby code that defines the shared method
+ attribute my_data
+ end
+
+ collect_data(:default) do
+ # some Ruby code
+ attribute my_data
+ end
+
+ collect_data(:platform...) do
+ # some Ruby code that defines platform-specific requirements
+ attribute my_data
+ end
+end
+```
+
+where
+
+- Required. `(:Name)` is used to identify the plugin; when two plugins have the same `(:Name)`, those plugins are joined together and run as if they were a single plugin. This value must be a valid Ruby class name, starting with a capital letter and containing only alphanumeric characters
+- Required. `provides` is a comma-separated list of one (or more) attributes that are defined by this plugin. This attribute will become an automatic attribute (`node['attribute']`) after it's collected by Ohai at the start of a Chef Infra Client run. An attribute can also be defined using an `attribute/subattribute` pattern
+- `depends` is a comma-separated list of one (or more) attributes that are collected by another plugin; as long as the value is collected by another Ohai plugin, it can be used by any plugin
+- `shared_method` defines code that can be shared among one (or more) `collect_data` blocks; for example, instead of defining a mash for each `collect_data` block, the code can be defined as a shared method, and then called from any `collect_data` block
+- `collect_data` is a block of Ruby code that's called by Ohai when it runs; one (or more) `collect_data` blocks can be defined in a plugin, but only a single `collect_data` block is ever run.
+- `collect_data(:default)` is the code block that runs when a node's platform isn't defined by a platform-specific `collect_data` block
+- `collect_data(:platform)` is a platform-specific code block that's run when a match exists between the node's platform and this `collect_data` block; only one `collect_data` block may exist for each platform; possible values: `:aix`, `:darwin`, `:freebsd`, `:linux`, `:openbsd`, `:netbsd`, `:solaris2`, `:windows`, or any other value from `RbConfig::CONFIG['host_os']`
+- `my_data` is string (`a string value`) or an empty mash (`{ :setting_a => 'value_a', :setting_b => 'value_b' }`). This is used to define the data that should be collected by the plugin
+
+For example, the following plugin looks up data on virtual machines hosted in Amazon EC2, Google Compute Engine, Rackspace, Eucalyptus, Linode, OpenStack, and Microsoft Azure:
+
+```ruby
+Ohai.plugin(:Cloud) do
+ provides 'cloud'
+
+ depends 'ec2'
+ depends 'gce'
+ depends 'rackspace'
+ depends 'eucalyptus'
+ depends 'linode'
+ depends 'openstack'
+ depends 'azure'
+
+ def create_objects
+ cloud Mash.new
+ cloud[:public_ips] = []
+ cloud[:private_ips] = []
+ end
+
+ ...
+
+ def on_gce?
+ gce != nil
+ end
+
+ def get_gce_values
+ cloud[:public_ipv4] = []
+ cloud[:local_ipv4] = []
+
+ public_ips = gce['instance']['networkInterfaces'].collect do |interface|
+ if interface.has_key?('accessConfigs')
+ interface['accessConfigs'].collect{|ac| ac['externalIp']}
+ end
+ end.flatten.compact
+
+ private_ips = gce['instance']['networkInterfaces'].collect do |interface|
+ interface['ip']
+ end.compact
+
+ cloud[:public_ips] += public_ips
+ cloud[:private_ips] += private_ips
+ cloud[:public_ipv4] += public_ips
+ cloud[:public_hostname] = nil
+ cloud[:local_ipv4] += private_ips
+ cloud[:local_hostname] = gce['instance']['hostname']
+ cloud[:provider] = 'gce'
+ end
+
+ ...
+
+ # with following similar code blocks for each cloud provider
+```
+
+where
+
+- `provides` defines the `cloud` attribute, which is then turned into an object using the `create_objects` shared method, which then generates a hash based on public or private IP addresses
+- For Google Compute Engine the `cloud` attribute data is populated into a hash based on the IP address for the node
+
+To see the rest of the code in this plugin, go to: .
+
+## Ohai Methods
+
+The Ohai DSL is a Ruby DSL that's used to define an Ohai plugin and to ensure that Ohai collects the right data at the start of every Chef Infra Client run. The Ohai DSL is a small DSL with a single method that's specific to Ohai plugins. Because the Ohai DSL is a Ruby DSL, anything that can be done using Ruby can also be done when defining an Ohai plugin.
+
+### collect_data
+
+The `collect_data` method is a block of Ruby code that's called by Ohai when it runs. One (or more) `collect_data` blocks can be defined in a plugin, but only a single `collect_data` block is ever run. The `collect_data` block that's run is determined by the platform on which the node is running, which is then matched up against the available `collect_data` blocks in the plugin.
+
+- A `collect_data(:default)` block is used when Ohai isn't able to match the platform of the node with a `collect_data(:platform)` block in the plugin
+- A `collect_data(:platform)` block is required for each platform that requires non-default behavior
+
+When Ohai runs, if there isn't a matching `collect_data` block for a platform, the `collect_data(:default)` block is used. The syntax for the `collect_data` method is:
+
+```ruby
+collect_data(:default) do
+ # some Ruby code
+end
+```
+
+or:
+
+```ruby
+collect_data(:platform) do
+ # some Ruby code
+end
+```
+
+where:
+
+- `:default` is the name of the default `collect_data` block
+- `:platform` is the name of a platform, such as `:aix` for AIX or `:windows` for Windows
+
+#### Use a Mash
+
+Use a mash to store data. This is done by creating a new mash, and then setting an attribute to it. For example:
+
+```ruby
+provides 'name_of_mash'
+name_of_mash Mash.new
+name_of_mash[:attribute] = 'value'
+```
+
+#### Examples
+
+The following examples show how to use the `collect_data` block:
+
+```ruby
+Ohai.plugin(:Azure) do
+ provides 'azure'
+
+ collect_data do
+ azure_metadata_from_hints = hint?('azure')
+ if azure_metadata_from_hints
+ Ohai::Log.debug('azure_metadata_from_hints is present.')
+ azure Mash.new
+ azure_metadata_from_hints.each {|k, v| azure[k] = v }
+ else
+ Ohai::Log.debug('No hints present for azure.')
+ false
+ end
+ end
+end
+```
+
+or:
+
+```ruby
+require 'ohai/mixin/ec2_metadata'
+extend Ohai::Mixin::Ec2Metadata
+
+Ohai.plugin do
+ provides 'openstack'
+
+ collect_data do
+ if hint?('openstack') || hint?('hp')
+ Ohai::Log.debug('ohai openstack')
+ openstack Mash.new
+ if can_metadata_connect?(EC2_METADATA_ADDR,80)
+ Ohai::Log.debug('connecting to the OpenStack metadata service')
+ self.fetch_metadata.each {|k, v| openstack[k] = v }
+ case
+ when hint?('hp')
+ openstack['provider'] = 'hp'
+ else
+ openstack['provider'] = 'openstack'
+ end
+ else
+ Ohai::Log.debug('unable to connect to the OpenStack metadata service')
+ end
+ else
+ Ohai::Log.debug('NOT ohai openstack')
+ end
+ end
+end
+```
+
+### require
+
+The `require` method is a standard Ruby method that can be used to list files that may be required by a platform, such as an external class library. As a best practice, even though the `require` method is often used at the top of a Ruby file, it's recommended that the use of the `require` method be used as part of the platform-specific `collect_data` block. For example, the Ruby WMI is required with Windows:
+
+```ruby
+collect_data(:windows) do
+ require 'ruby-wmi'
+ WIN32OLE.codepage = WIN32OLE::CP_UTF8
+
+ kernel Mash.new
+
+ host = WMI::Win32_OperatingSystem.find(:first)
+ kernel[:os_info] = Mash.new
+ host.properties_.each do |p|
+ kernel[:os_info][p.name.wmi_underscore.to_sym] = host.send(p.name)
+ end
+
+ ...
+
+end
+```
+
+Ohai will attempt to fully qualify the name of any class by prepending `Ohai::` to the loaded class. For example both:
+
+```ruby
+require Ohai::Mixin::ShellOut
+```
+
+and:
+
+```ruby
+require Mixin::ShellOut
+```
+
+are both understood by the Ohai in the same way: `Ohai::Mixin::ShellOut`.
+
+When a class is an external class (and therefore shouldn't have `Ohai::` prepended), use `::` to let the Ohai know. For example:
+
+```ruby
+::External::Class::Library
+```
+
+#### /common Directory
+
+The `/common` directory stores code that's used across all Ohai plugins. For example, a file in the `/common` directory named `virtualization.rb` that includes code like the following:
+
+```ruby
+module Ohai
+ module Common
+ module Virtualization
+
+ def host?(virtualization)
+ !virtualization.nil? && virtualization[:role].eql?('host')
+ end
+
+ def open_virtconn(system)
+ begin
+ require 'libvirt'
+ require 'hpricot'
+ rescue LoadError => e
+ Ohai::Log.debug('Cannot load gem: #{e}.')
+ end
+
+ emu = (system.eql?('kvm') ? 'qemu' : system)
+ virtconn = Libvirt::open_read_only('#{emu}:///system')
+ end
+
+ ...
+
+ def networks(virtconn)
+ networks = Mash.new
+ virtconn.list_networks.each do |n|
+ nv = virtconn.lookup_network_by_name n
+ networks[n] = Mash.new
+ networks[n][:xml_desc] = (nv.xml_desc.split('\n').collect {|line| line.strip}).join
+ ['bridge_name','uuid'].each {|a| networks[n][a] = nv.send(a)}
+ #xdoc = Hpricot networks[n][:xml_desc]
+ end
+ networks
+ end
+
+ ...
+
+ end
+ end
+end
+```
+
+can then be leveraged in a plugin by using the `require` method to require the `virtualization.rb` file and then later calling each of the methods in the required module:
+
+```ruby
+require 'ohai/common/virtualization'
+
+Ohai.plugin(:Virtualization) do
+ include Ohai::Common::Virtualization
+
+ provides 'virtualization'
+ %w{ capabilities domains networks storage }.each do |subattr|
+ provides 'virtualization/#{subattr}'
+ end
+
+ collect_data(:linux) do
+ virtualization Mash.new
+
+ ...
+
+ if host?(virtualization)
+ v = open_virtconn(virtualization[:system])
+
+ virtualization[:libvirt_version] = libvirt_version(v)
+ virtualization[:nodeinfo] = nodeinfo(v)
+ virtualization[:uri] = uri(v)
+ virtualization[:capabilities] = capabilities(v)
+ virtualization[:domains] = domains(v)
+ virtualization[:networks] = networks(v)
+ virtualization[:storage] = storage(v)
+
+ close_virtconn(v)
+ end
+```
+
+### Shared Methods
+
+Use shared methods to define objects for use in `collect_data` blocks, such as a data structure, a hash, or a mash. The syntax for a shared method is:
+
+```ruby
+def a_shared_method
+ # some Ruby code that defines the shared method
+end
+```
+
+The following example declares a shared `cloud` method to collect data about cloud providers based on the type of IP address and then uses the `cloud` object to collect data from different cloud providers.
+
+Create `cloud` objects based on the type of IP address:
+
+```ruby
+def create_objects
+ cloud Mash.new
+ cloud[:public_ips] = Array.new
+ cloud[:private_ips] = Array.new
+end
+```
+
+Use `cloud` object to collect Linode data:
+
+```ruby
+def get_linode_values
+ cloud[:public_ips] << linode['public_ip']
+ cloud[:private_ips] << linode['private_ip']
+ cloud[:public_ipv4] = linode['public_ipv4']
+ cloud[:public_hostname] = linode['public_hostname']
+ cloud[:local_ipv4] = linode['local_ipv4']
+ cloud[:local_hostname] = linode['local_hostname']
+ cloud[:provider] = 'linode'
+end
+```
+
+Use the `cloud` object to collect Azure data:
+
+```ruby
+def get_azure_values
+ cloud[:vm_name] = azure['vm_name']
+ cloud[:public_ips] << azure['public_ip']
+ cloud[:public_fqdn] = azure['public_fqdn']
+ cloud[:public_ssh_port] = azure['public_ssh_port'] if azure['public_ssh_port']
+ cloud[:public_winrm_port] = azure['public_winrm_port'] if azure['public_winrm_port']
+ cloud[:provider] = 'azure'
+end
+```
+
+## Logging
+
+Use the `Ohai::Log` class in an Ohai plugin to define log entries that are created by Ohai. The syntax for a log message is as follows:
+
+```ruby
+Ohai::Log.log_type('message')
+```
+
+where
+
+- `log_type` can be `.debug`, `.info`, `.warn`, `.error`, or `.fatal`
+- `'message'` is the message that's logged.
+
+For example:
+
+```ruby
+Ohai.plugin do
+ provides 'openstack'
+
+ collect_data do
+ if hint?('openstack') || hint?('hp')
+ Ohai::Log.debug('ohai openstack')
+ openstack Mash.new
+ if can_metadata_connect?(EC2_METADATA_ADDR,80)
+ Ohai::Log.debug('connecting to the OpenStack metadata service')
+ self.fetch_metadata.each {|k, v| openstack[k] = v }
+ case
+ when hint?('hp')
+ openstack['provider'] = 'hp'
+ else
+ openstack['provider'] = 'openstack'
+ end
+ else
+ Ohai::Log.debug('unable to connect to the OpenStack metadata service')
+ end
+ else
+ Ohai::Log.debug('NOT ohai openstack')
+ end
+ end
+end
+```
+
+### rescue
+
+Use the `rescue` clause to make sure that a log message is always provided. For example:
+
+```ruby
+rescue LoadError => e
+ Ohai::Log.debug('ip_scopes: can't load gem, plugin disabled: #{e}')
+end
+```
+
+## Examples
+
+The following examples show different ways of building Ohai plugins.
+
+### collect_data Blocks
+
+The following Ohai plugin uses multiple `collect_data` blocks and shared methods to define platforms:
+
+```ruby
+Ohai.plugin(:Hostname) do
+ provides 'domain', 'fqdn', 'hostname'
+
+ def from_cmd(cmd)
+ so = shell_out(cmd)
+ so.stdout.split($/)[0]
+ end
+
+ def collect_domain
+ if fqdn
+ fqdn =~ /.+?\.(.*)/
+ domain $1
+ end
+ end
+
+ collect_data(:aix, :hpux) do
+ hostname from_cmd('hostname -s')
+ fqdn from_cmd('hostname')
+ domain collect_domain
+ end
+
+ collect_data(:darwin, :netbsd, :openbsd) do
+ hostname from_cmd('hostname -s')
+ fqdn from_cmd('hostname')
+ domain collect_domain
+ end
+
+ collect_data(:freebsd) do
+ hostname from_cmd('hostname -s')
+ fqdn from_cmd('hostname -f')
+ domain collect_domain
+ end
+
+ collect_data(:linux) do
+ hostname from_cmd('hostname -s')
+ begin
+ fqdn from_cmd('hostname --fqdn')
+ rescue
+ Ohai::Log.debug('hostname -f returned an error, probably no domain is set')
+ end
+ domain collect_domain
+ end
+
+ collect_data(:solaris2) do
+ require 'socket'
+
+ hostname from_cmd('hostname')
+
+ fqdn_lookup = Socket.getaddrinfo(hostname, nil, nil, nil, nil, Socket::AI_CANONNAME).first[2]
+ if fqdn_lookup.split('.').length > 1
+ # we received an fqdn
+ fqdn fqdn_lookup
+ else
+ # default to assembling one
+ h = from_cmd('hostname')
+ d = from_cmd('domainname')
+ fqdn '#{h}.#{d}'
+ end
+
+ domain collect_domain
+ end
+
+ collect_data(:windows) do
+ require 'ruby-wmi'
+ require 'socket'
+
+ host = WMI::Win32_ComputerSystem.find(:first)
+ hostname '#{host.Name}'
+
+ info = Socket.gethostbyname(Socket.gethostname)
+ if info.first =~ /.+?\.(.*)/
+ fqdn info.first
+ else
+ # host isn't in dns. optionally use:
+ # C:\WINDOWS\system32\drivers\etc\hosts
+ fqdn Socket.gethostbyaddr(info.last).first
+ end
+
+ domain collect_domain
+ end
+end
+```
+
+### Use a mixin Library
+
+The following Ohai example shows a plugin can use a `mixin` library and also depend on another plugin:
+
+```ruby
+require 'ohai/mixin/os'
+
+Ohai.plugin(:Os) do
+ provides 'os', 'os_version'
+ depends 'kernel'
+
+ collect_data do
+ os collect_os
+ os_version kernel[:release]
+ end
+end
+```
+
+### Get Kernel Values
+
+The following Ohai example shows part of a file that gets initial kernel attribute values:
+
+```ruby
+Ohai.plugin(:Kernel) do
+ provides 'kernel', 'kernel/modules'
+
+ def init_kernel
+ kernel Mash.new
+ [['uname -s', :name], ['uname -r', :release],
+ ['uname -v', :version], ['uname -m', :machine]].each do |cmd, property|
+ so = shell_out(cmd)
+ kernel[property] = so.stdout.split($/)[0]
+ end
+ kernel
+ end
+
+ ...
+
+ collect_data(:darwin) do
+ kernel init_kernel
+ kernel[:os] = kernel[:name]
+
+ so = shell_out('sysctl -n hw.optional.x86_64')
+ if so.stdout.split($/)[0].to_i == 1
+ kernel[:machine] = 'x86_64'
+ end
+
+ modules = Mash.new
+ so = shell_out('kextstat -k -l')
+ so.stdout.lines do |line|
+ if line =~ /(\d+)\s+(\d+)\s+0x[0-9a-f]+\s+0x([0-9a-f]+)\s+0x[0-9a-f]+\s+([a-zA-Z0-9\.]+) \(([0-9\.]+)\)/
+ kext[$4] = { :version => $5, :size => $3.hex, :index => $1, :refcount => $2 }
+ end
+ end
+
+ kernel[:modules] = modules
+ end
+
+ ...
+```
diff --git a/content/extension_apis/dsl_handler.md b/content/extension_apis/dsl_handler.md
new file mode 100644
index 0000000..00738f6
--- /dev/null
+++ b/content/extension_apis/dsl_handler.md
@@ -0,0 +1,73 @@
++++
+title = "About the Handler DSL"
+draft = false
+
+[menu]
+ [menu.extension_apis]
+ title = "Handler DSL"
+ identifier = "extension_apis/handlers/dsl_handler.md Handler DSL"
+ parent = "extension_apis/handlers"
+ weight = 20
++++
+
+{{< readfile file="content/reusable/md/dsl_handler_summary.md" >}}
+
+## on Method
+
+{{< readfile file="content/reusable/md/dsl_handler_method_on.md" >}}
+
+## Event Types
+
+{{< readfile file="content/reusable/md/dsl_handler_event_types.md" >}}
+
+## Examples
+
+The following examples show ways to use the Handler DSL.
+
+### Send Email
+
+{{< readfile file="content/reusable/md/dsl_handler_slide_send_email.md" >}}
+
+#### Define How Email is Sent
+
+{{< readfile file="content/reusable/md/dsl_handler_slide_send_email_library.md" >}}
+
+#### Add the Handler
+
+{{< readfile file="content/reusable/md/dsl_handler_slide_send_email_handler.md" >}}
+
+#### Test the Handler
+
+{{< readfile file="content/reusable/md/dsl_handler_slide_send_email_test.md" >}}
+
+### etcd Locks
+
+{{< readfile file="content/reusable/md/dsl_handler_example_etcd_lock.md" >}}
+
+### HipChat Notifications
+
+{{< readfile file="content/reusable/md/dsl_handler_example_hipchat.md" >}}
+
+### `attribute_changed` event hook
+
+In a cookbook library file, you can add this to print out all
+attribute changes in cookbooks:
+
+```ruby
+Chef.event_handler do
+ on :attribute_changed do |precedence, key, value|
+ puts "setting attribute #{precedence}#{key.map { |n| "[\"#{n}\"]" }.join} = #{value}"
+ end
+end
+```
+
+If you want to setup a policy that override attributes should never be
+used:
+
+```ruby
+Chef.event_handler do
+ on :attribute_changed do |precedence, key, value|
+ raise 'override policy violation' if precedence == :override
+ end
+end
+```
diff --git a/content/features/_index.md b/content/features/_index.md
new file mode 100644
index 0000000..8fd114d
--- /dev/null
+++ b/content/features/_index.md
@@ -0,0 +1,5 @@
++++
+title = "Features"
+
+list_pages = true
++++
\ No newline at end of file
diff --git a/content/agentless/_index.md b/content/features/agentless/_index.md
similarity index 89%
rename from content/agentless/_index.md
rename to content/features/agentless/_index.md
index a711f82..70682ec 100644
--- a/content/agentless/_index.md
+++ b/content/features/agentless/_index.md
@@ -1,12 +1,14 @@
+++
-title = "Chef Infra Agentless Mode"
+title = "About Agentless Mode"
+draft = false
linkTitle = "Agentless"
-[menu.agentless]
-title = "Agentless overview"
-identifier = "agentless/overview"
-parent = "agentless"
-weight = 10
+[menu]
+ [menu.features]
+ title = "About Agentless Mode"
+ identifier = "features/agentless/About"
+ parent = "features/agentless"
+ weight = 10
+++
{{< readfile file="content/reusable/md/agentless_summary.md" >}}
@@ -29,7 +31,7 @@ Agentless Mode has the following requirements:
- A network-enabled system to execute Agentless Mode.
- The `chef-client` CLI. This is included with Chef Workstation.
-- A [credentials file](#target-credentials-file) that provides the system with information to connect to a target node.
+- A [target credentials file](#target-credentials-file) that provides the system with information to connect to a target node.
- A recipe that only includes [Agentless Mode-enabled resources](#resources).
## Target credentials file
@@ -171,37 +173,6 @@ Additional parameters:
-### Retrieve secrets from HashiCorp Vault
-
-You can configure Agentless Mode to fetch secrets from HashiCorp Vault.
-
-In the `~/.chef/target_credentials` file, define the following:
-
-- your Vault authentication settings with the `default_secrets_provider` hash
-- your secret name saved in Vault
-
-For example:
-
-```toml
-default_secrets_provider = {
- name = 'hashicorp-vault',
- endpoint = '',
- token = ''
-}
-
-['']
-host = ''
-user = ''
-sudo = true
-password = { secret = '', field = 'password' }
-```
-
-Replace:
-
-- `` with your Vault endpoint, for example: `http://127.0.0.1:8200`.
-- `` with your Vault token, for example: `hvs.ewUEnIRVaKoBzs2...example...ewUEnIRVaKoBzs2`.
-- `` with the name of the secret stored in Vault.
-
## Resources
All resources included in a Cookbook must be enabled in Agentless Mode to run in Agentless Mode.
@@ -230,7 +201,7 @@ chef-client -t
Replace `` with the name of the host as defined in the credentials file.
For example, `HOST-1` in the [credential file example](#define-node-connections).
-To execute a specific cookbook in Agentless Mode, run:
+To execute a specific Cookbook in Agentless Mode, run:
```sh
chef-client -t
@@ -239,9 +210,9 @@ chef-client -t
Replace the following:
- `` with the name of the host as defined in the credentials file.
-- `` with the path to the Cookbook on your system. For example, `/chef-repo/cookbooks/example_cookbook.rb`
+- `` with the path to the Cookbook on your system. For example, `/chef-repo/cookbooks/example_cookbook`. This runs the default recipe in the cookbook.
-### Run Agentless Mode in Local Mode
+### Agentless Mode in Local Mode
You can run Agentless Mode in Local Mode.
Local Mode runs chef-zero locally as a lightweight instance of Chef Infra Server to execute a Client run on target nodes.
@@ -252,10 +223,11 @@ Use `-z` and `-t` to run Agentless Mode in Local Mode:
chef-client -z -t
```
-You can also run a specific cookbook in Local Mode:
+Replace `` with the name of the host as defined in the credentials file.
+For example, `HOST-1` in the [credential file example](#define-node-connections).
```sh
-chef-client -z -t
+chef-client -z -t
```
Replace:
@@ -263,7 +235,7 @@ Replace:
- `` with the name of the host as defined in the credentials file.
For example, `HOST-1` in the [credential file example](#define-node-connections).
-- `` with the cookbook file path. For example, `/chef-repo/cookbooks-dir/cookbook1.rb`.
+- `` with the recipe file path inside a cookbook. For example, `/chef-repo/cookbooks/cookbook1/recipe1.rb`.
You should see output similar to this:
diff --git a/content/agentless/example.md b/content/features/agentless/example.md
similarity index 79%
rename from content/agentless/example.md
rename to content/features/agentless/example.md
index 0c90d62..9ff3bbd 100644
--- a/content/agentless/example.md
+++ b/content/features/agentless/example.md
@@ -1,22 +1,22 @@
+++
title = "Chef Infra Agentless Mode example"
-[menu.agentless]
+[menu.features]
title = "Agentless Mode example"
-identifier = "agentless/example"
-parent = "agentless"
+identifier = "features/agentless/example"
+parent = "features/agentless"
weight = 20
+++
This document provides a simplified, end-to-end guide to configure and run
-Chef Infra Client 19 RC3 in Agentless (Target Mode) using Habitat (`hab`)
+Chef Infra Client in Agentless (Target Mode) using Habitat (`hab`)
for managing remote systems.
## Prerequisites
- [Chef Infra Client is installed](/install/)
- Your `HAB_AUTH_TOKEN` is exported
-- a valid Progress Chef license key
+- You have a valid Progress Chef license key
## Create a target credentials file
@@ -37,10 +37,12 @@ user = 'root'
password = ''
```
-For more information, see the [target credentials file documentation](/agentless/).
+For more information, see the [target credentials file documentation](/features/agentless/).
## Create the test recipe
+
+
On the host, create a test recipe file (`~/.chef/apply.rb`) with the test resources below.
{{< foundation_tabs tabs-id="test-agentless-mode-recipe" >}}
@@ -116,9 +118,11 @@ end
{{< /foundation_tabs_panel >}}
{{< /foundation_tabs_panels >}}
-## Run the recipe in Agentless Mode
+
+
+## Run Agentless Mode using Habitat
-From your `.chef` directory, execute the recipe withe Chef Infra Client:
+From your `.chef` directory, with `HAB_AUTH_TOKEN` exported and the license key available:
```sh
cd ~/.chef
@@ -129,6 +133,27 @@ Replace `` with the target name defined in the `target_credentials`
Chef Infra Client executes the `apply.rb` recipe in local mode (`chef-client -z`) against the remote target (`-t `) over SSH using the credentials defined in `~/.chef/target_credentials`.
+## Run a recipe using a run list in Agentless Mode
+
+Instead of specifying a recipe, you can run a recipe by specifying it in a run list using the `-r` option.
+This requires the cookbook to be available locally in your cookbook path.
+
+For example, to run the `example_cookbook::default` recipe:
+
+```sh
+chef-client -z -t -r 'recipe[example_cookbook::default]'
+```
+
+Replace `` with the target name defined in the `target_credentials` file.
+
+If the cookbook is uploaded to Chef Infra Server, you can upload the cookbook, add it to the node's run list, and then run Chef Infra Client in target mode:
+
+```sh
+knife cookbook upload example_cookbook
+knife node run_list add 'recipe[example_cookbook::default]'
+chef-client -t
+```
+
## Verify the output
A successful Infra Client run returns something like this:
diff --git a/content/features/agentless/resources/_index.md b/content/features/agentless/resources/_index.md
new file mode 100644
index 0000000..de7ca42
--- /dev/null
+++ b/content/features/agentless/resources/_index.md
@@ -0,0 +1,107 @@
++++
+title = "Supported Chef Infra resources in Agentless Mode"
+linkTitle = "Supported resources"
+
+[menu.features]
+title = "Supported resources"
+identifier = "features/agentless/resources/overview"
+parent = "features/agentless/resources"
+weight = 10
++++
+
+
+
+The following Chef Infra resources are supported in Agentless Mode.
+
+| **Resources Name** | **Verified Platforms** | **Remarks** |
+|---|---|---|
+| [alternatives](/resources/bundled/alternatives/) | Ubuntu, Linux | |
+| [apt_package](/resources/bundled/apt_package/) | Ubuntu | |
+| [apt_preference](/resources/bundled/apt_preference/) | Ubuntu, Linux | |
+| [apt_repository](/resources/bundled/apt_repository/) | Ubuntu, Linux | |
+| [apt_update](/resources/bundled/apt_update/) | Ubuntu, Linux | |
+| [bash](/resources/bundled/bash/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
+| [breakpoint](/resources/bundled/breakpoint/) | Ubuntu, Linux | |
+| [chef_acl](/resources/bundled/chef_acl/) | Ubuntu, Linux, CentOS 9 | |
+| [chef_client](/resources/bundled/chef_client/) | Ubuntu 24.04, Linux Red Hat 9, Solaris, Alpine, SUSE | |
+| [chef_client_config](/resources/bundled/chef_client_config/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
+| [chef_container](/resources/bundled/chef_container/) | Ubuntu, Linux | |
+| [chef_data_bag](/resources/bundled/chef_data_bag/) | Ubuntu, Linux | |
+| [chef_environment](/resources/bundled/chef_environment/) | Ubuntu, Linux | |
+| [chef_group](/resources/bundled/chef_group/) | Ubuntu 24.04 and 18.04, RHEL | |
+| [chef_node](/resources/bundled/chef_node/) | Ubuntu 24.04, Linux Red Hat 9 | |
+| [chef_organization](/resources/bundled/chef_organization/) | Ubuntu 24.04 and 18.04, RHEL | |
+| [chef_role](/resources/bundled/chef_role/) | Ubuntu 24.04, Linux Red Hat 9, Solaris, Alpine, SUSE | |
+| [chef_sleep](/resources/bundled/chef_sleep/) | Ubuntu, Linux | |
+| [chef_user](/resources/bundled/chef_user/) | Ubuntu 24.04 and 18.04, RHEL, Solaris, Alpine, SUSE | |
+| [cookbook_file](/resources/bundled/cookbook_file/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
+| [cron](/resources/bundled/cron/) | Ubuntu, Linux, Solaris SunOS, Alpine | |
+| [cron_access](/resources/bundled/cron_access/) | Ubuntu, Linux, Solaris SunOS, Alpine | |
+| [cron_d](/resources/bundled/cron_d/) | Ubuntu, Linux | |
+| [csh](/resources/bundled/csh/) | Ubuntu 24.04, Linux Red Hat 9, Alpine | |
+| [directory](/resources/bundled/directory/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
+| [execute](/resources/bundled/execute/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
+| [file](/resources/bundled/file/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
+| [freebsd_package](/resources/bundled/freebsd_package/) | FreeBSD 14 | Supported on FreeBSD. |
+| [git](/resources/bundled/git/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
+| [group](/resources/bundled/group/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
+| [habitat_config](/resources/bundled/habitat_config/) | Ubuntu 24.04, Linux Red Hat 9, Solaris, Alpine, SUSE | |
+| [habitat_install](/resources/bundled/habitat_install/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
+| [habitat_package](/resources/bundled/habitat_package/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
+| [habitat_service](/resources/bundled/habitat_service/) | Ubuntu, Linux | |
+| [habitat_sup](/resources/bundled/habitat_sup/) | Ubuntu, Linux | |
+| [hostname](/resources/bundled/hostname/) | Ubuntu, Linux | |
+| [http_request](/resources/bundled/http_request/) | Ubuntu, Linux, , Solaris, Alpine, SUSE | |
+| [ifconfig](/resources/bundled/ifconfig/) | Ubuntu, Linux | |
+| [inspec_input](/resources/bundled/inspec_input/) | Ubuntu 24.04, Linux Red Hat 9 | |
+| [inspec_waiver](/resources/bundled/inspec_waiver/) | Ubuntu, Linux | |
+| [inspec_waiver_file_entry](/resources/bundled/inspec_waiver_file_entry/) | Ubuntu, Linux | |
+| [kernel_module](/resources/bundled/kernel_module/) | Ubuntu, Linux | |
+| [ksh](/resources/bundled/ksh/) | Ubuntu 24.04, Linux Red Hat 9, Solaris, Alpine, SUSE | |
+| [link](/resources/bundled/link/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
+| [locale](/resources/bundled/locale/) | Ubuntu | |
+| [log](/resources/bundled/log/) | Ubuntu, Linux, Solaris, Alpine, SUSE | |
+| [mount](/resources/bundled/mount/) | Ubuntu 24.04, CentOS 9 | |
+| [notify_group](/resources/bundled/notify_group/) | Ubuntu, Linux | |
+| [ohai](/resources/bundled/ohai/) | Ubuntu, Linux | |
+| [ohai_hint](/resources/bundled/ohai_hint/) | Ubuntu, Linux | |
+| [package](/resources/bundled/package/) | Ubuntu, Linux, CentOS 9, Solaris, Alpine, SUSE | |
+| [perl](/resources/bundled/perl/) | Ubuntu | |
+| [python](/resources/bundled/python/) | Ubuntu 24.04, Linux Red Hat 9, Solaris, Alpine, SUSE | |
+| [reboot](/resources/bundled/reboot/) | Ubuntu, Linux | |
+| [remote_file](/resources/bundled/remote_file/) | Ubuntu, Linux, CentOS 9, Solaris, Alpine, SUSE | |
+| [rhsm_errata](/resources/bundled/rhsm_errata/) | Linux (redhat) | |
+| [rhsm_errata_level](/resources/bundled/rhsm_errata_level/) | Linux (redhat) | |
+| [rhsm_register](/resources/bundled/rhsm_register/) | Linux (redhat) | |
+| [rhsm_repo](/resources/bundled/rhsm_repo/) | Linux (redhat) | |
+| [rhsm_subscription](/resources/bundled/rhsm_subscription/) | Linux (redhat) | |
+| [route](/resources/bundled/route/) | Ubuntu 24.04 / CentOS 9 | |
+| [rpm_package](/resources/bundled/rpm_package/) | CentOS 9 | The RPM package must be locally available on the remote system. |
+| [ruby_block](/resources/bundled/ruby_block/) | Ubuntu, Linux, CentOS 9 | |
+| [script](/resources/bundled/script/) | Ubuntu 24.04, Linux Red Hat 9, , Solaris, Alpine | |
+| [selinux_boolean](/resources/bundled/selinux_boolean/) | Ubuntu, Linux | |
+| [selinux_fcontext](/resources/bundled/selinux_fcontext/) | Ubuntu, Linux | |
+| [selinux_install](/resources/bundled/selinux_install/) | Ubuntu, Linux | |
+| [selinux_login](/resources/bundled/selinux_login/) | Ubuntu, Linux | |
+| [selinux_module](/resources/bundled/selinux_module/) | Ubuntu, Linux | |
+| [selinux_permissive](/resources/bundled/selinux_permissive/) | Ubuntu, Linux | |
+| [selinux_port](/resources/bundled/selinux_port/) | Ubuntu, Linux | |
+| [selinux_state](/resources/bundled/selinux_state/) | Ubuntu, Linux | |
+| [selinux_user](/resources/bundled/selinux_user/) | Ubuntu, Linux | |
+| [service](/resources/bundled/service/) | Ubuntu, Linux, CentOS 9, Solaris, Alpine, SUSE | `crond` for Linux |
+| [snap_package](/resources/bundled/snap_package/) | Ubuntu 24.04 | Supported on Linux. |
+| [ssh_known_hosts_entry](/resources/bundled/ssh_known_hosts_entry/) | Ubuntu, Linux | |
+| [subversion](/resources/bundled/subversion/) | Ubuntu 24.04, Linux Red Hat 9, CentOS 9 | The subversion resource has known bugs and may not work as expected. For more information, see the Chef GitHub issues [#4050](https://github.com/chef/chef/issues/4050) and [#4257](https://github.com/chef/chef/issues/4257). |
+| [sudo](/resources/bundled/sudo/) | Ubuntu, Linux, CentOS 9, Solaris, Alpine, SUSE | |
+| [swap_file](/resources/bundled/swap_file/) | Ubuntu, Linux | |
+| [sysctl](/resources/bundled/sysctl/) | Ubuntu, Linux | |
+| [systemd_unit](/resources/bundled/systemd_unit/) | Ubuntu, Linux | |
+| [template](/resources/bundled/template/) | Ubuntu, Linux, CentOS 9, Solaris, Alpine, SUSE | Require absolute path for source attribute. |
+| [timezone](/resources/bundled/timezone/) | Linux, Solaris, Alpine, SUSE | |
+| [user](/resources/bundled/user/) | Ubuntu, Linux | |
+| [user_ulimit](/resources/bundled/user_ulimit/) | Ubuntu, Linux | |
+| [yum_package](/resources/bundled/yum_package/) | CentOS 9 | Supported on Linux. |
+| [yum_repository](/resources/bundled/yum_repository/) | Linux | |
+| [yum_repository](/resources/bundled/yum_repository/) | CentOS 9, RHEL 8 | Supported on Linux. |
+| [zypper_package](/resources/bundled/zypper_package/) | SUSE Linux 15 | |
+| [solaris_package](/resources/bundled/solaris_package/) | Solaris | |
diff --git a/content/agentless/resources/custom.md b/content/features/agentless/resources/custom.md
similarity index 96%
rename from content/agentless/resources/custom.md
rename to content/features/agentless/resources/custom.md
index c23071f..3eedfc9 100644
--- a/content/agentless/resources/custom.md
+++ b/content/features/agentless/resources/custom.md
@@ -2,10 +2,10 @@
title = "Custom resource guide"
[menu]
- [menu.agentless]
+ [menu.features]
title = "Custom resource guide"
- identifier = "agentless/resources/custom"
- parent = "agentless"
+ identifier = "features/agentless/resources/custom"
+ parent = "features/agentless/resources"
weight = 10
+++
diff --git a/content/features/chef_compliance_phase.md b/content/features/chef_compliance_phase.md
new file mode 100644
index 0000000..0f227c2
--- /dev/null
+++ b/content/features/chef_compliance_phase.md
@@ -0,0 +1,663 @@
++++
+title = "About the Compliance Phase"
+draft = false
+
+[menu]
+ [menu.features]
+ title = "Compliance Phase"
+ identifier = "features/chef_compliance_phase.md Compliance Phase"
+ parent = "features"
+ weight = 15
+
++++
+
+
+Chef Infra Client's Compliance Phase lets you automatically execute compliance audits and view the results as part of any Chef Infra Client run. The Compliance Phase of the Chef Infra Client run replaces the legacy [audit cookbook](https://supermarket.chef.io/cookbooks/audit) and works with your existing audit cookbook attributes, and you can also set it up for new cookbooks. This additional phase gives you the latest compliance capabilities without having to manage cookbook dependencies or juggle versions during Chef Infra Client updates.
+
+Existing audit cookbook users can migrate to the new Compliance Phase by removing the audit cookbook from their run_list and setting the `node['audit']['compliance_phase']` attribute to `true`.
+
+The Compliance Phase replaces the `audit cookbook` by integrating Chef InSpec compliance checks into the [Chef Infra Client run]({{< relref "/" >}})
+The Compliance Phase is designed to run on any node in your system that's set up--or [bootstrapped]({{< relref "install_bootstrap" >}})--for a `chef-client` run.
+
+Once turned on, the Compliance Phase always outputs its results in the CLI on manual runs. The output for automated runs is handled by [reporters]({{< relref "#reporters" >}}).
+
+## Upgrade to Compliance Phase from Audit Cookbook
+
+The Compliance Phase requires Chef Infra Client 17 or higher.
+
+If your system is configured to use the `audit cookbook`, make these changes to switch to the Compliance Phase:
+
+1. Set the `node['audit']['compliance_phase']` attribute to `true` through a Policyfile or cookbook attributes file.
+1. Remove the `audit cookbook` from your [run-list]({{< relref "run_lists.md" >}}).
+
+1. On your next Chef Infra Client run, you should see the Compliance Phase results.
+
+## Set up the Compliance Phase in new Cookbooks
+
+### Turn on the Compliance Phase
+
+Turn on the Compliance Phase by setting the `node['audit']['compliance_phase']` attribute to `true` through cookbook attributes or Policyfiles. To turn on Compliance Phase using cookbook attributes add the following line to the `attributes/default.rb` file in your cookbook.
+
+```ruby
+default['audit']['compliance_phase'] = true
+```
+
+### Set Chef InSpec Profiles
+
+Setting one or more Chef InSpec profiles turns on the Compliance Phase in a Chef Infra Client run. The presence of this configuration in your attributes file instructs Chef Infra Client to fetch and execute the specific Chef InSpec profiles and write the results to disk using the default `cli` and `json-file` reporters.
+
+Retrieve [Chef InSpec profiles](https://docs.chef.io/inspec/profiles/) from Chef Automate, Supermarket, a local file, GitHub, or over HTTP with the `node['audit']['profiles']` attribute.
+
+The following examples:
+
+- Retrieve profiles from Chef Automate, Supermarket, a local file, GitHub, or over HTTP.
+- Display the results on the command line using the default `cli` reporter.
+- Write the results to disk using the default `json-file` reporter to `/compliance_reports/compliance-.json`.
+
+
+
+{{< foundation_tabs tabs-id="compliance-phase-profile-panel" >}}
+ {{< foundation_tab active="true" panel-link="automate-panel" tab-text="Automate">}}
+ {{< foundation_tab panel-link="supermarket-panel" tab-text="Supermarket" >}}
+ {{< foundation_tab panel-link="local-path-panel" tab-text="File" >}}
+ {{< foundation_tab panel-link="git-panel" tab-text="GitHub" >}}
+ {{< foundation_tab panel-link="http-panel" tab-text="HTTP" >}}
+{{< /foundation_tabs >}}
+{{< foundation_tabs_panels tabs-id="compliance-phase-profile-panel" >}}
+ {{< foundation_tabs_panel active="true" panel-id="automate-panel" >}}
+ ```ruby
+ # Invoke the Compliance Phase
+ default['audit']['compliance_phase'] = true
+ # Set profile locations
+ default['audit']['profiles']['linux-baseline'] = {
+ 'compliance': 'user/linux-baseline',
+ 'version': '2.1.0'
+ }
+ ```
+ {{< warning >}}
+ Fetching profiles from Chef Automate requires setting `data_collector.server_url` and `data_collector.token` in your `client.rb` to fetch profiles from Chef Automate. This configuration is described in more detail in the Chef Automate [data collector documentation](https://docs.chef.io/automate/data_collection/).
+ {{< /warning >}}
+ {{< /foundation_tabs_panel >}}
+ {{< foundation_tabs_panel panel-id="supermarket-panel" >}}
+ ```ruby
+ # Invoke the Compliance Phase
+ default['audit']['compliance_phase'] = true
+ # Set profile locations
+ default['audit']['profiles']['ssh'] = {
+ 'supermarket': 'hardening/ssh-hardening'
+ }
+ ```
+ {{< /foundation_tabs_panel >}}
+ {{< foundation_tabs_panel panel-id="local-path-panel" >}}
+ ```ruby
+ # Invoke the Compliance Phase
+ default['audit']['compliance_phase'] = true
+ # Set profile locations
+ default['audit']['profiles']['4thcafe/win2012_audit'] = {
+ 'path': 'E:/profiles/win2012_audit'
+ }
+ ```
+ {{< /foundation_tabs_panel >}}
+ {{< foundation_tabs_panel panel-id="git-panel" >}}
+ ```ruby
+ # Invoke the Compliance Phase
+ default['audit']['compliance_phase'] = true
+ # Set profile locations
+ default['audit']['profiles']['ssl'] = {
+ 'git': 'https://github.com/dev-sec/ssl-benchmark.git'
+ }
+ ```
+ {{< /foundation_tabs_panel >}}
+ {{< foundation_tabs_panel panel-id="http-panel" >}}
+ ```ruby
+ # Invoke the Compliance Phase
+ default['audit']['compliance_phase'] = true
+ # Set profile locations
+ default['audit']['profiles']['ssh2'] = {
+ 'url': 'https://github.com/dev-sec/tests-ssh-hardening/archive/master.zip'
+ }
+ ```
+ {{< /foundation_tabs_panel >}}
+{{< /foundation_tabs_panels >}}
+
+
+
+### Fetch Profiles
+
+Set the fetcher attribute with `default['audit']['fetcher']` to retrieve Chef InSpec compliance profiles from either Chef Automate or Chef Infra Server in addition to the location defined by `default ['audit']['profile']`. Left unset, the Compliance Phase defaults to the [fetchers included in Chef InSpec](https://docs.chef.io/inspec/profiles#profile-dependencies). Chef Infra and Chef InSpec fetchers are mutually exclusive so, you can only use one of these configurations.
+
+The following examples:
+
+- Retrieve the 'ssh' profile from Chef Supermarket.
+- Fetch additional profiles from Chef Automate or Chef Infra Server.
+- Display the results on the command line using the default `cli` reporter.
+- Write the results to disk using the default `json-file` reporter to `/compliance_reports/compliance-.json`.
+
+
+
+{{< foundation_tabs tabs-id="compliance-phase-fetcher-panel" >}}
+ {{< foundation_tab active="true" panel-link="automate-fetcher" tab-text="Automate">}}
+ {{< foundation_tab panel-link="server-fetcher" tab-text="Infra Server" >}}
+{{< /foundation_tabs >}}
+{{< foundation_tabs_panels tabs-id="compliance-phase-fetcher-panel" >}}
+ {{< foundation_tabs_panel active="true" panel-id="automate-fetcher" >}}
+ ```ruby
+ # Invoke the Compliance Phase
+ default['audit']['compliance_phase'] = true
+ # Set profile location
+ default['audit']['profiles']['ssh'] = {
+ 'supermarket': 'hardening/ssh-hardening'
+ }
+ # Fetch additional profiles
+ default['audit']['fetcher'] = 'chef-automate'
+ ```
+ {{< warning >}}
+ Fetching profiles from Chef Automate requires setting `data_collector.server_url` and `data_collector.token` in your `client.rb` to fetch profiles from Chef Automate. This configuration is described in more detail in the Chef Automate [data collector documentation](https://docs.chef.io/automate/data_collection/).
+ {{< /warning >}}
+ {{< /foundation_tabs_panel >}}
+ {{< foundation_tabs_panel panel-id="server-fetcher" >}}
+ ```ruby
+ # Invoke the Compliance Phase
+ default['audit']['compliance_phase'] = true
+ # Set profile location
+ default['audit']['profiles']['ssh'] = {
+ 'supermarket': 'hardening/ssh-hardening'
+ }
+ # Fetch additional profiles
+ default['audit']['fetcher'] = 'chef-server'
+ ```
+ {{< /foundation_tabs_panel >}}
+{{< /foundation_tabs_panels >}}
+
+
+
+### Reporters
+
+Reporters control what's done with the resulting report after the Chef InSpec run. Either a single value or a list of multiple values is supported. The default is the `cli` and `json-file` reporters.
+
+Reporters can send Compliance Phase results to:
+
+- Chef Automate proxied by Chef Infra Server.
+- Directly to Chef Automate (requires additional authentication).
+- The terminal if Chef Infra Client is run interactively by a user.
+- A file on disk.
+
+The following examples:
+
+- Retrieve the 'ssh' profile from Chef Supermarket
+- Fetch additional profiles from Chef Automate
+- Send the results to Chef Automate, Chef Automate proxied by Chef Infra Server, or to a file on disk.
+
+
+
+{{< foundation_tabs tabs-id="compliance-phase-reporter-panel" >}}
+ {{< foundation_tab active="true" panel-link="automate-reporter" tab-text="Automate">}}
+ {{< foundation_tab panel-link="server-reporter" tab-text="Automate using Infra Server" >}}
+ {{< foundation_tab panel-link="local-reporter" tab-text="File" >}}
+{{< /foundation_tabs >}}
+{{< foundation_tabs_panels tabs-id="compliance-phase-reporter-panel" >}}
+ {{< foundation_tabs_panel active="true" panel-id="automate-reporter" >}}
+ ```ruby
+ # Invoke the Compliance Phase
+ default['audit']['compliance_phase'] = true
+ # Set profile location
+ default['audit']['profiles']['ssh'] = {
+ 'supermarket': 'hardening/ssh-hardening'
+ }
+ # Fetch additional profiles
+ default['audit']['fetcher'] = 'chef-automate'
+ # Set reporter
+ default['audit']['reporter'] = 'chef-automate'
+ ```
+ {{< warning >}}
+ Reporting Compliance Phase results directly to Chef Automate requires setting `data_collector.server_url` and `data_collector.token` in your `client.rb` to fetch profiles from Chef Automate. This configuration is described in more detail in the Chef Automate [data collector documentation](https://docs.chef.io/automate/data_collection/).
+ {{< /warning >}}
+ {{< /foundation_tabs_panel >}}
+ {{< foundation_tabs_panel panel-id="server-reporter" >}}
+ ```ruby
+ # Invoke the Compliance Phase
+ default['audit']['compliance_phase'] = true
+ # Set profile location
+ default['audit']['profiles']['ssh'] = {
+ 'supermarket': 'hardening/ssh-hardening'
+ }
+ # Fetch additional profiles
+ default['audit']['fetcher'] = 'chef-server'
+ # Set reporter
+ default['audit']['reporter'] = 'chef-server-automate'
+ ```
+
+ {{< /foundation_tabs_panel >}}
+ {{< foundation_tabs_panel panel-id="local-reporter" >}}
+ ```ruby
+ # Invoke the Compliance Phase
+ default['audit']['compliance_phase'] = true
+ # Set profile location
+ default['audit']['profiles']['ssh'] = {
+ 'supermarket': 'hardening/ssh-hardening'
+ }
+ # Fetch additional profiles
+ default['audit']['fetcher'] = 'chef-automate'
+ # Set two reporters
+ default['audit']['reporter'] = 'json-file', 'cli'
+ # Set the location of the json-file output
+ # Note that the location attribute uses json_file
+ default['audit']['json_file']['location'] = '/file/path/report.json'
+ ```
+
+ The default `json-file` path is: `/compliance_reports/compliance-.json`.
+
+ The path will also be output to the Chef Infra Client log:
+
+ ```bash
+ ['2017-08-29T00:22:10+00:00'] INFO: Reporting to json-file
+ ['2017-08-29T00:22:10+00:00'] INFO: Writing report to /opt/kitchen/cache/compliance-reports/compliance-20170829002210.json
+ ['2017-08-29T00:22:10+00:00'] INFO: Report handlers complete
+ ```
+
+ {{< /foundation_tabs_panel >}}
+{{< /foundation_tabs_panels >}}
+
+
+
+## Customize Profiles
+
+You can upload profiles to Chef Automate using the [Chef Automate API](https://docs.chef.io/automate/api/#operation/Create) or the `inspec compliance` command.
+
+### Waivers
+
+Use [waivers](https://docs.chef.io/inspec/waivers/) to mark individual failing controls as administratively accepted, either on a temporary or permanent basis.
+
+To use waivers:
+
+1. Prepare a YAML waiver file.
+1. Deliver the waiver file to the node in a [cookbook_file]({{< relref "/resources/bundled/cookbook_file" >}}) or [remote_file]({{< relref "/resources/bundled/remote_file" >}}).
+1. Set the `waiver_file` attribute for the Compliance Phase to that location. For example:
+
+```ruby
+default['audit']['waiver_file'] = "waivers.yaml"
+```
+
+### External Data
+
+Chef InSpec profiles should be self-contained and independent from external data. Sometimes, a profile's test may exhibit different behavior depending on aspects of the node being tested and in these cases, you may want to use external data. Chef InSpec profiles accept [inputs](https://docs.chef.io/inspec/inputs/) that let you customize the test.
+
+#### Chef InSpec Input
+
+You can pass [Chef InSpec inputs](https://docs.chef.io/inspec/inputs/) to the Chef InSpec runner. Chef InSpec inputs were previously called `attributes` and you will set them in an `['audit']['attributes']` hash in your attributes file.
+Any data added to `['audit']['attributes']` as a hash is passed to Chef InSpec as individual attributes.
+
+ ```ruby
+ default['audit']['attributes'] = {
+ first_input: 'some value',
+ second_input: 'another value',
+ }
+ ```
+
+#### Chef Node Data
+
+There are two primary ways to pass Chef Infra node data to Chef InSpec run during the Compliance Phase.
+
+##### Explicitly pass necessary data (recommended)
+
+Any data added to the `node['audit']['attributes']` hash will be passed as individual Chef InSpec attributes. This provides a clean interface between the Chef Infra client run and Chef InSpec profile, allowing for easy assignment of default values in the Chef InSpec profile. This method is especially recommended if the Chef InSpec profile is expected to be used outside of the context of Compliance Phase so it's made explicit to profile consumers what attributes are necessary. Set the attributes in your cookbook attributes file and then use them in your Chef InSpec profile.
+
+Set the attributes in a cookbook attributes file:
+
+```ruby
+node['audit']['attributes']{
+ 'key1' = 'value1',
+ 'debug_enabled' = node['my_cookbook']['debug_enabled'],
+ 'environment' = node.chef_environment
+}
+```
+
+Use the attributes in a Chef InSpec profile:
+
+```ruby
+environment = attribute('environment', description: 'The Chef Infra environment for the node', default: 'dev')
+
+control 'debug-disabled-in-production' do
+ title 'Debug logs disabled in production'
+ desc 'Debug logs contain potentially sensitive information and shouldn't be on in production.'
+ impact 1.0
+
+ describe file('/path/to/my/app/config') do
+ its('content') { should_not include "debug=true" }
+ end
+
+ only_if { environment == 'production' }
+end
+```
+
+#### Use the Chef Infra Node Object
+
+Compliance Phase can be configured to pass the Chef Infra node object as a Chef InSpec attribute named `chef_node`.
+
+While using the `chef_node` object provides the ability to write more flexible profiles, it's difficult to reuse these profiles outside of the Compliance Phase. To reuse these profiles, you will need to understand how to pass in a single attribute containing Chef Infra-like data. Pass external data explicitly whenever possible.
+
+To use this option, first set it in a wrapper cookbook:
+
+```ruby
+node.override['audit']['chef_node_attribute_enabled'] = true
+```
+
+And then use it in your profile:
+
+```ruby
+chef_node = attribute('chef_node', description: 'Chef Node')
+
+control 'no-password-auth-in-prod' do
+ title 'No Password Authentication in Production'
+ desc 'Password authentication is allowed in all environments except production'
+ impact 1.0
+
+ describe sshd_config do
+ its('PasswordAuthentication') { should cmp 'No' }
+ end
+
+ only_if { chef_node['chef_environment'] == 'production' }
+end
+```
+
+## Useful Compliance Phase Attributes
+
+### audit-enforcer
+
+A special reporter that causes the compliance run to raise an error and immediately terminates the Chef Infra Client run if any control of any Chef InSpec profile fails. If you specify multiple reporters, place the `audit-enforcer` at the end of the list, allowing the other reporters to generate their output before run termination. Example:
+
+```ruby
+# fail on error
+default['audit']['reporter'] = 'audit-enforcer'.
+```
+
+### chef_node_attribute_enabled
+
+If set, a hash representation of the Chef Infra node object will be sent to an input named `chef_node`. Default: false
+
+```ruby
+# send a hash representation of the Chef Infra node object
+default['audit']['chef_node_attribute_enabled'] = true
+```
+
+### compliance_phase
+
+Turn on the built-in Compliance Phase run. Possible values: true, false, nil
+
+```ruby
+# Turn on Compliance Phase
+default['audit']['compliance_phase] = true
+```
+
+### control_results_limit
+
+The list of results for each control will be truncated to this amount to reduce the size of reports. A summary of removed results will be sent with each impacted control. Defaults to `50`.
+
+```ruby
+# allow 100 results
+ default['audit']['control_results_limit'] = 100
+```
+
+### fetcher
+
+Controls the location for additional profile locations for Chef InSpec profiles default fetch locations provided through the `[audit][profiles]` attribute. Accepted values: nil, 'chef-server', 'chef-automate'.
+
+```ruby
+# fetch additional profiles from Chef Infra Server
+default[audit][fetcher] = 'chef-server'
+```
+
+### insecure
+
+Setting the attribute `default['audit']['insecure']` to `true` will skip SSL certificate verification for the `chef-automate` and `chef-server-automate` reporters. This allows connections to HTTPS endpoints with self-signed ssl certificates. Default is `false`
+
+```ruby
+# allow self-signed certificates
+default['audit']['insecure'] = true
+```
+
+### interval
+
+You can control the frequency of Compliance Phase scans with the `default['audit']['interval']`, which means that control the frequency that the Compliance Phase runs with a Chef Infra Client run. This helps you control the impact of compliance scans on system performance in business environments that require compliance scans less frequently than Chef Infra Client Runs.
+
+`default['audit']['interval']['enabled']`
+: Set to true to turn on interval runs.
+
+ ```ruby
+ # Set independent Compliance Phase scans
+ default['audit']['interval']['enabled'] = true
+ ```
+
+`default['audit']['interval']['time']`
+: The time in minutes between Compliance Phase execution. Default: 1440 (once a day).
+
+ ```ruby
+ # Define the timing of independent Compliance Phase scans
+ # Sets scan to twice daily
+ default['audit']['interval']['time'] = 1220
+ ```
+
+### json_file
+
+The location on disk that Chef InSpec's json reports are saved to when using the 'json-file' reporter. Defaults to: `/compliance_reports/compliance-.json`
+
+```ruby
+default['audit']['reporter'] = 'json-file'
+default['audit']['json_file']['location'] = '/path/to/file.json'
+```
+
+### inspec_backend_cache
+
+Chef InSpec caches the results of commands executed on the node during the Compliance Phase. Caching improves the Compliance Phase performance when slower-running commands are executed multiple times during a Chef Infra Client run. Disable this feature if your Chef InSpec profile runs a command multiple times expecting different output during the run. Default: true. Example:
+
+```ruby
+# Disable caching of commands
+default['audit']['inspec_backend_cache'] = false
+```
+
+### profiles
+
+Chef InSpec Compliance profiles to be used for scanning nodes.
+
+```ruby
+# use the ssh-hardening profile from Supermarket
+default['audit']['profiles']['ssh'] = {
+ 'supermarket': 'hardening/ssh-hardening'
+ }
+```
+
+### quiet
+
+Starting in Chef Infra Client 18.7, use `quiet` to suppress output of the Chef InSpec runner. Defaults to `false`.
+
+To suppress InSpec runner output, set to `true`:
+
+```ruby
+# verbose
+default['audit']['quiet'] = true
+```
+
+### reporter
+
+Controls what's done with the resulting report after the Chef InSpec run. Accepts a single string value or an array of multiple values. The 'cli' reporter mimics the Chef InSpec command line output in your terminal, which lets you see your system's compliance status at the end of the Compliance Phase. Accepted values: 'chef-server-automate', 'chef-automate', 'json-file', 'audit-enforcer', 'cli'
+
+```ruby
+# set the reporter to Chef Automate
+default['audit']['reporter'] = 'chef-automate', 'cli'
+```
+
+### run_time_limit
+
+Control results that have a `run_time` below this limit will be stripped of the `start_time` and `run_time` fields to reduce the size of reports. Defaults to `1.0`. Set this attribute with `default['audit']['run_time_limit']`.
+
+```ruby
+# allow 5 minutes run time
+default['audit']['run_time_limit'] = 5.0
+```
+
+### result_include_backtrace
+
+When a Chef InSpec resource throws an exception, results contain a short error message and a detailed ruby stacktrace of the error. Default: false (doesn't send backtrace). Example:
+
+```ruby
+# include backtrace
+default['audit']['result_include_backtrace'] = true
+```
+
+### result_message_limit
+
+Truncates any control result messages exceeding this character limit. Chef Automate has a 4 MB report size limit and can't ingest reports exceeding this limitation. Chef InSpec will append this text at the end of any truncated messages: `[Truncated to 10000 characters]` Default: 10000.
+
+```ruby
+default['audit']['result_message_limit] = 10000
+```
+
+### server
+
+When reporting to a Chef Automate instance proxied over Chef Infra Server, the Compliance Phase can be configured to use a different URL than the `chef_server_url` configured in `client.rb`. Turn on with the attribute `default['audit']['server']`.
+
+```ruby
+default['audit']['server'] = 'https://server.4thcafe.com'.
+```
+
+### waiver_file
+
+A string path or an array of paths to Chef InSpec waiver files.
+
+```ruby
+default['audit']['waiver_file'] = 'path/to/waiver.yml'.
+```
+
+## Errors and Troubleshooting
+
+### Cache Results
+
+Chef InSpec caches the results of commands executed on the node during the Compliance Phase. Caching improves the Compliance Phase performance when slower-running commands are executed multiple times during a Chef Infra Client run. Disable this feature if your Chef InSpec profile runs a command multiple times expecting different output during the run. Default: true. Example:
+
+```ruby
+# Disable caching of commands
+default['audit']['inspec_backend_cache'] = false
+```
+
+### Chef InSpec Report Size Limits
+
+The size of the report being generated from running the Compliance Phase is influenced by a few factors like:
+
+- number of controls and tests in a profile
+- number of profile failures for the node
+- controls metadata (title, description, tags, etc)
+- number of resources (users, processes, etc) that are being tested
+
+Depending on your setup, there are some limits you need to be aware of. A common one is Chef Infra Server default (1MB) request size. Exceeding this limit will reject the report with `ERROR: 413 "Request Entity Too Large"`. For more details about these limits, please refer to [the documentation on troubleshooting 413 errors](#413-request-entity-too-large).
+
+### HTTP Errors
+
+#### 401, 403 Unauthorized - bad clock
+
+Occasionally, the system date/time will drift between client and server. If this drift is greater than a couple of minutes, Chef Infra Server will throw a 401 unauthorized and the request won't be forwarded to the Chef Automate server.
+
+On Chef Infra Server you can see this in the following logs:
+
+```text
+# chef-server-ctl tail
+
+==> /var/log/opscode/nginx/access.log <==
+192.168.200.102 - - ['28/Aug/2016:14:57:36 +0000'] "GET /organizations/4thcafe/nodes/vagrant-c0971990 HTTP/1.1" 401 "0.004" 93 "-" "Chef Infra Client/12.14.38 (ruby-2.3.1-p112; ohai-8.19.2; x86_64-linux; +https://chef.io)" "127.0.0.1:8000" "401" "0.003" "12.14.38" "algorithm=sha1;version=1.1;" "vagrant-c0971990" "2013-09-25T15:00:14Z" "2jmj7l5rSw0yVb/vlWAYkK/YBwk=" 1060
+
+==> /var/log/opscode/opscode-erchef/crash.log <==
+2016-08-28 14:57:36 =ERROR REPORT====
+{<<"method=GET; path=/organizations/4thcafe/nodes/vagrant-c0971990; status=401; ">>,"Unauthorized"}
+
+==> /var/log/opscode/opscode-erchef/erchef.log <==
+2016-08-28 14:57:36.521 ['error'] {<<"method=GET; path=/organizations/4thcafe/nodes/vagrant-c0971990; status=401; ">>,"Unauthorized"}
+
+==> /var/log/opscode/opscode-erchef/current <==
+2016-08-28_14:57:36.52659 ['error'] {<<"method=GET; path=/organizations/4thcafe/nodes/vagrant-c0971990; status=401; ">>,"Unauthorized"}
+
+==> /var/log/opscode/opscode-erchef/requests.log.1 <==
+2016-08-28T14:57:36Z erchef@127.0.0.1 method=GET; path=/organizations/4thcafe/nodes/vagrant-c0971990; status=401; req_id=g3IAA2QAEGVyY2hlZkAxMjcuMC4wLjEBAAOFrgAAAAAAAAAA; org_name=4thcafe; msg=bad_clock; couchdb_groups=false; couchdb_organizations=false; couchdb_containers=false; couchdb_acls=false; 503_mode=false; couchdb_associations=false; couchdb_association_requests=false; req_time=1; user=vagrant-c0971990; req_api_version=1;
+```
+
+Additionally, the chef_gate log will contain a similar message:
+
+```text
+# /var/log/opscode/chef_gate/current
+2016-08-28_15:01:34.88702 ['GIN'] 2016/08/28 - 15:01:34 | 401 | 13.650403ms | 192.168.200.102 | POST /compliance/organizations/4thcafe/inspec
+2016-08-28_15:01:34.88704 Error #01: Authentication failed. Please check your system's clock.
+```
+
+#### 401 Token and Refresh Token Authentication
+
+In the event of a malformed or unset token, the Chef Automate server will log the token error:
+
+```text
+==> /var/log/chef-compliance/core/current <==
+2016-08-28_20:41:46.17496 20:41:46.174 ERR => Token authentication: %!(EXTRA *errors.errorString=malformed JWS, only 1 segments)
+2016-08-28_20:41:46.17498 ['GIN'] 2016/08/28 - 20:41:46 | 401 | 53.824us | 192.168.200.102 | GET /owners/base/compliance/linux/tar
+
+==> /var/log/chef-compliance/nginx/compliance.access.log <==
+192.168.200.102 - - ['28/Aug/2016:21:23:46 +0000'] "GET /api/owners/base/compliance/linux/tar HTTP/1.1" 401 0 "-" "Ruby"
+```
+
+#### 413 Request Entity Too Large
+
+This error indicates that you have exceeded limit the `erchef` request size in Chef Infra Server. The default for versions before 13.0 was 1MB. Starting with version 13.0 the default is 2MB.
+
+To resolve this error, set the `opscode_erchef['max_request_size']` in Chef Infra Server's `/etc/opscode/chef-server.rb` to a larger amount. This example sets the limit to 3MB:
+
+```ruby
+opscode_erchef['max_request_size'] = 3000000
+```
+
+Then run `chef-server-ctl reconfigure` to apply this change.
+
+##### 413 Error Logs
+
+The 413 "Request Entity Too Large" error appears in both the stacktrace and Chef Infra Server Nginx logs.
+
+
+
+{{< foundation_tabs tabs-id="compliance-413-panel" >}}
+ {{< foundation_tab active="true" panel-link="413-stacktrace" tab-text="Stacktrace">}}
+ {{< foundation_tab panel-link="413-server-nginx" tab-text="Nginx logs" >}}
+{{< /foundation_tabs >}}
+{{< foundation_tabs_panels tabs-id="compliance-413-panel" >}}
+ {{< foundation_tabs_panel active="true" panel-id="413-stacktrace" >}}
+ The stacktrace shows the 413 error:
+ ```text
+ Running handlers:
+ ['2017-12-21T16:21:15+00:00'] WARN: Compliance report size is 1.71 MB.
+ ['2017-12-21T16:21:15+00:00'] ERROR: 413 "Request Entity Too Large" (Net::HTTPServerException)
+ /opt/chef/embedded/lib/ruby/2.4.0/net/http/response.rb:122:in `error!'
+ /opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.6.4/lib/chef/http.rb:152:in `request'
+ /opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.6.4/lib/chef/http.rb:131:in `post'
+ /var/chef/cache/cookbooks/audit/libraries/reporters/cs_automate.rb:37:in `block in send_report'
+ ...
+ ```
+ {{< /foundation_tabs_panel >}}
+ {{< foundation_tabs_panel panel-id="413-server-nginx" >}}
+ The Chef Infra Server Nginx log confirms the `413` error:
+ ```text
+ ==> /var/log/opscode/nginx/access.log <==
+ 192.168.56.40 - - ['21/Dec/2017:11:35:30 +0000'] "POST /organizations/eu_org/data-collector HTTP/1.1" 413 "0.803" 64 "-" "Chef Infra Client/13.6.4 (ruby-2.4.2-p198; ohai-13.6.0; x86_64-linux; +https://chef.io)" "-" "-" "-" "13.6.4" "algorithm=sha1;version=1.1;" "bootstrapped-node" "2017-12-21T11:35:31Z" "GR6RyPvKkZDaGyQDYCPfoQGS8G4=" 1793064
+ ```
+ {{< /foundation_tabs_panel >}}
+
+{{< /foundation_tabs_panels >}}
+
+
+
+## Troubleshooting
+
+Chef Automate sets the `logstash` limit to 10% of the system memory automatically as part of the `automate-ctl reconfigure` command execution. You have reached the java heap size(`-Xmx`) limit of `logstash` if a Chef InSpec report doesn't become available in Chef Automate and this error is in the `logstash` logs:
+
+```text
+/var/log/delivery/logstash/current
+2017-12-21_13:59:54.69949 DEBUG: Ruby filter is processing an 'inspec_profile' event
+2017-12-21_14:00:16.51553 java.lang.OutOfMemoryError: Java heap space
+2017-12-21_14:00:16.51556 Dumping heap to /opt/delivery/embedded/logstash/heapdump.hprof ...
+2017-12-21_14:00:16.51556 Unable to create /opt/delivery/embedded/logstash/heapdump.hprof: File exists
+2017-12-21_14:00:18.50676 Error: Your application used more memory than the safety cap of 383M.
+2017-12-21_14:00:18.50694 Specify -J-Xmx####m to increase it (#### = cap size in MB).
+2017-12-21_14:00:18.50703 Specify -w for full OutOfMemoryError stack trace
+```
diff --git a/content/features/chef_search.md b/content/features/chef_search.md
new file mode 100644
index 0000000..1777520
--- /dev/null
+++ b/content/features/chef_search.md
@@ -0,0 +1,384 @@
++++
+title = "About Search"
+draft = false
+
+[menu]
+ [menu.features]
+ title = "Search"
+ identifier = "features/chef_search.md Search"
+ parent = "features"
+ weight = 70
++++
+
+{{< readfile file="content/reusable/md/search.md" >}}
+
+Many of the examples in this section use knife, but the search indexes
+and search query syntax can be used in many locations, including from
+within recipes and when using the Chef Infra Server API.
+
+## Search Indexes
+
+A search index is a full-text list of objects that are stored on the
+Chef Infra Server, against which search queries can be made. The
+following search indexes are built:
+
+
+
+
+
+
+
+
+
+
+
+client |
+API client |
+
+
+DATA_BAG_NAME |
+A data bag is a global variable that's stored as JSON data and is accessible from a Chef Infra Server. The name of the search index is the name of the data bag. For example, if the name of the data bag was "admins" then a corresponding search query might look something like search(:admins, "*:*"). |
+
+
+environment |
+An environment is a way to map an organization's real-life workflow to what can be configured and managed when using Chef Infra Server. |
+
+
+node |
+A node is any server or virtual server that's configured to be maintained by a Chef Infra Client. |
+
+
+role |
+A role is a way to define certain patterns and processes that exist across nodes in an organization as belonging to a single job function. |
+
+
+
+
+### Using Knife
+
+{{< readfile file="content/reusable/md/workstation/knife_search_summary.md" >}}
+
+#### Search by platform ID
+
+{{< readfile file="content/reusable/md/workstation/knife_search_by_platform_ids.md" >}}
+
+#### Search by instance type
+
+{{< readfile file="content/reusable/md/workstation/knife_search_by_platform_instance_type.md" >}}
+
+#### Search by recipe
+
+{{< readfile file="content/reusable/md/workstation/knife_search_by_recipe.md" >}}
+
+#### Search by cookbook, then recipe
+
+{{< readfile file="content/reusable/md/workstation/knife_search_by_cookbook.md" >}}
+
+#### Search by node
+
+{{< readfile file="content/reusable/md/workstation/knife_search_by_node.md" >}}
+
+#### Search by node and environment
+
+{{< readfile file="content/reusable/md/workstation/knife_search_by_node_and_environment.md" >}}
+
+#### Search for nested attributes
+
+{{< readfile file="content/reusable/md/workstation/knife_search_by_nested_attribute.md" >}}
+
+#### Search for multiple attributes
+
+{{< readfile file="content/reusable/md/workstation/knife_search_by_query_for_many_attributes.md" >}}
+
+#### Search for nested attributes using a search query
+
+{{< readfile file="content/reusable/md/workstation/knife_search_by_query_for_nested_attribute.md" >}}
+
+#### Use a test query
+
+{{< readfile file="content/reusable/md/workstation/knife_search_test_query_for_ssh.md" >}}
+
+## Query Syntax
+
+{{< readfile file="content/reusable/md/search_query_syntax.md" >}}
+
+{{< note >}}
+
+Search queries may not contain newlines.
+
+{{< /note >}}
+
+## Filter Search Results
+
+{{< readfile file="content/reusable/md/infra_lang_method_search_filter_result.md" >}}
+
+## Keys
+
+{{< readfile file="content/reusable/md/search_key.md" >}}
+
+### Nested Fields
+
+{{< readfile file="content/reusable/md/search_key_nested.md" >}}
+
+### Examples
+
+{{< readfile file="content/reusable/md/search_key_name.md" >}}
+
+{{< readfile file="content/reusable/md/search_key_wildcard_question_mark.md" >}}
+
+{{< readfile file="content/reusable/md/search_key_wildcard_asterisk.md" >}}
+
+{{< readfile file="content/reusable/md/search_key_nested_starting_with.md" >}}
+
+{{< readfile file="content/reusable/md/search_key_nested_range.md" >}}
+
+## Patterns
+
+{{< readfile file="content/reusable/md/search_pattern.md" >}}
+
+### Exact Matching
+
+{{< readfile file="content/reusable/md/search_pattern_exact.md" >}}
+
+{{< readfile file="content/reusable/md/search_pattern_exact_key_and_item.md" >}}
+
+{{< readfile file="content/reusable/md/search_pattern_exact_key_and_item_string.md" >}}
+
+### Wildcard Matching
+
+{{< readfile file="content/reusable/md/search_pattern_wildcard.md" >}}
+
+{{< readfile file="content/reusable/md/search_pattern_wildcard_any_node.md" >}}
+
+{{< readfile file="content/reusable/md/search_pattern_wildcard_node_contains.md" >}}
+
+### Range Matching
+
+{{< readfile file="content/reusable/md/search_pattern_range.md" >}}
+
+{{< readfile file="content/reusable/md/search_pattern_range_in_between.md" >}}
+
+{{< readfile file="content/reusable/md/search_pattern_range_exclusive.md" >}}
+
+### Fuzzy Matching
+
+{{< readfile file="content/reusable/md/search_pattern_fuzzy.md" >}}
+
+{{< readfile file="content/reusable/md/search_pattern_fuzzy_summary.md" >}}
+
+## Operators
+
+{{< readfile file="content/reusable/md/search_boolean_operators.md" >}}
+
+{{< readfile file="content/reusable/md/search_boolean_operators_andnot.md" >}}
+
+### AND
+
+{{< readfile file="content/reusable/md/search_boolean_and.md" >}}
+
+### NOT
+
+{{< readfile file="content/reusable/md/search_boolean_not.md" >}}
+
+### OR
+
+{{< readfile file="content/reusable/md/search_boolean_or.md" >}}
+
+## Special Characters
+
+{{< readfile file="content/reusable/md/search_special_characters.md" >}}
+
+## Targets
+
+A search target is any object that has been indexed on the Chef Infra
+Server, including roles (and run-lists), nodes, environments, data bags,
+and any API client.
+
+### Roles in Run-lists
+
+A search query can be made for roles that are at the top-level of a
+run-list and also for a role that's part of an expanded run-list.
+
+{{< note >}}
+
+The `roles` field is updated with each Chef Infra Client run; changes to
+a run-list won't affect `roles` until the next Chef Infra Client run
+on the node.
+
+{{< /note >}}
+
+
+
+
+
+
+
+
+
+
+
+Top-level |
+To find a node with a role in the top-level of its run-list, search within the role field (and escaping any special characters with the slash symbol) using the following syntax:
+role:ROLE_NAME
+where role (singular!) indicates the top-level run-list. |
+
+
+Expanded |
+To find a node with a role in an expanded run-list, search within the roles field (and escaping any special characters with the slash symbol) using the following syntax:
+roles:ROLE_NAME
+where roles (plural!) indicates the expanded run-list. |
+
+
+
+
+To search a top-level run-list for a role named `load_balancer` use the
+`knife search` subcommand from the command line or the `search` method
+in a recipe. For example:
+
+```bash
+knife search node role:load_balancer
+```
+
+and from within a recipe:
+
+```ruby
+search(:node, 'role:load_balancer')
+```
+
+To search an expanded run-list for all nodes with the role
+`load_balancer` use the `knife search` subcommand from the command line
+or the `search` method in a recipe. For example:
+
+```bash
+knife search node roles:load_balancer
+```
+
+and from within a recipe:
+
+```ruby
+search(:node, 'roles:load_balancer')
+```
+
+### Nodes
+
+A node can be searched from a recipe by using the following syntax:
+
+```ruby
+search(:node, "key:attribute")
+```
+
+A wildcard can be used to replace characters within the search query.
+
+Expanded lists of roles (all of the roles that apply to a node,
+including nested roles) and recipes to the role and recipe attributes on
+a node are saved on Chef Infra Server. The expanded lists of roles
+allows for searching within nodes that run a given recipe, even if that
+recipe is included by a role.
+
+{{< note >}}
+
+The `recipes` field is with each Chef Infra Client run; changes to a
+run-list won't affect `recipes` until the next Chef Infra Client run
+on the node.
+
+{{< /note >}}
+
+
+
+
+
+
+
+
+
+
+
+In a specified recipe |
+To find a node with a specified recipe in the run-list, search within the run_list field (and escaping any special characters with the slash symbol) using the following syntax:
+search(:node, 'run_list:recipe\[foo\:\:bar\]')
+where recipe (singular!) indicates the top-level run-list. Variables can be interpolated into search strings using the Ruby alternate quoting syntax:
+search(:node, %Q{run_list:"recipe[#{the_recipe}]"} )
|
+
+
+In an expanded run-list |
+To find a node with a recipe in an expanded run-list, search within the recipes field (and escaping any special characters with the slash symbol) using the following syntax:
+
+where recipes (plural!) indicates to search within an expanded run-list. |
+
+
+
+
+If you just want to use each result of the search and don't care about
+the aggregate result you can provide a code block to the search method.
+Each result is then passed to the block:
+
+```ruby
+# Print every node matching the search pattern
+search(:node, "*:*").each do |matching_node|
+ puts matching_node.to_s
+end
+```
+
+### API Clients
+
+An API client is any machine that has permission to use the Chef Infra
+Server API to communicate with Chef Infra Server. An API client is
+typically a node (that runs Chef Infra Client) or a workstation (that
+runs knife), but can also be any other machine configured to use the
+Chef Infra Server API.
+
+Sometimes when a role isn't fully defined (or implemented), it may be
+necessary for a machine to connect to a database, search engine, or some
+other service within an environment by using the settings located on
+another machine, such as a host name, IP address, or private IP address.
+The following example shows a simplified settings file:
+
+```ruby
+username: "mysql"
+password: "MoveAlong"
+host: "10.40.64.202"
+port: "3306"
+```
+
+where `host` is the private IP address of the database server. Use the
+following knife query to view information about the node:
+
+```bash
+knife search node "name:name_of_database_server" --long
+```
+
+To access these settings as part of a recipe that's run on the web
+server, use code similar to:
+
+```ruby
+db_server = search(:node, "name:name_of_database_server")
+private_ip = "#{db_server[0][:rackspace][:private_ip]}"
+puts private_ip
+```
+
+where the "\[0\]" is the 0 (zero) index for the `db_server` identifier.
+A single document is returned because the node is being searched on its
+unique name. The identifier `private_ip` will now have the value of the
+private IP address of the database server (`10.40.64.202`) and can then
+be used in templates as a variable, among other possible uses.
+
+### Environments
+
+{{< readfile file="content/reusable/md/environment.md" >}}
+
+{{< readfile file="content/reusable/md/search_environment.md" >}}
+
+### Data Bags
+
+{{< readfile file="content/reusable/md/data_bag.md" >}}
+
+{{< readfile file="content/reusable/md/search_data_bag.md" >}}
diff --git a/content/features/chef_solo/_index.md b/content/features/chef_solo/_index.md
new file mode 100644
index 0000000..ce01733
--- /dev/null
+++ b/content/features/chef_solo/_index.md
@@ -0,0 +1,162 @@
++++
+title = "chef-solo"
+draft = false
+
+[menu]
+ [menu.features]
+ title = "About Chef Solo"
+ identifier = "features/chef_solo/chef_solo.md About Chef Solo"
+ parent = "features/chef_solo"
+ weight = 10
++++
+
+{{< readfile file="content/reusable/md/chef_solo_summary.md" >}}
+
+## Cookbooks
+
+chef-solo supports two locations from which cookbooks can be run:
+
+- A local directory.
+- A URL at which a tar.gz archive is located.
+
+Using a tar.gz archive is the more common approach, but requires that
+cookbooks be added to an archive. For example:
+
+```bash
+tar zcvf chef-solo.tar.gz ./cookbooks
+```
+
+If you use multiple cookbook directories, chef-solo expects the
+tar.gz archive to have a directory structure similar to the following:
+
+```text
+. cookbooks
+├── cookbook-name-1
+│ └── attributes
+└── cookbook-name-2
+ └── attributes
+```
+
+The `cookbook_path` variable in the solo.rb file must include both
+directories. For example:
+
+```bash
+tar zcvf chef-solo.tar.gz ./cookbooks ./site-cookbooks
+```
+
+When the tar.gz archive contains all of the cookbooks required by
+chef-solo, upload it to the web server from which chef-solo will access
+the archive.
+
+## Nodes
+
+Unlike Chef Infra Client, where the node object is stored on the Chef
+Infra Server, chef-solo stores its node objects as JSON files on local
+disk. By default, chef-solo stores these files in a `nodes` folder in
+the same directory as your `cookbooks` directory. You can control the
+location of this directory using the `node_path` value in your
+configuration file.
+
+## Attributes
+
+chef-solo doesn't interact with Chef Infra Server. Consequently,
+node-specific attributes must be located in a JSON file on the target
+system, a remote location (such as Amazon Simple Storage Service (S3)),
+or a web server on the local network.
+
+The JSON file must also specify the recipes that are part of the
+run-list. For example:
+
+```json
+{
+ "resolver": {
+ "nameservers": [ "10.0.0.1" ],
+ "search":"int.example.com"
+ },
+ "run_list": [ "recipe[resolver]" ]
+}
+```
+
+## Data bags
+
+A data bag is defined using JSON. chef-solo will look for data bags in
+`/var/chef/data_bags`, but this location can be modified by changing the
+setting in solo.rb. For example, the following setting in solo.rb:
+
+```ruby
+data_bag_path '/var/chef-solo/data_bags'
+```
+
+Create a data bag by creating folders. For example:
+
+```bash
+mkdir /var/chef-solo/data_bags
+```
+
+and:
+
+```bash
+mkdir /var/chef-solo/data_bags/admins
+```
+
+and then create a JSON file in that location:
+
+```json
+{
+ "id": "ITEM_NAME"
+}
+```
+
+where the name of the file is the `ITEM_NAME`, for example:
+
+```ruby
+/var/chef-solo/data_bags/admins/ITEM_NAME.json
+```
+
+## Roles
+
+A role is defined using JSON or the Ruby DSL. chef-solo will look for
+roles in `/var/chef/roles`, but this location can be modified by
+changing the setting for `role_path` in solo.rb. For example, the
+following setting in solo.rb:
+
+```ruby
+role_path '/var/chef-solo/roles'
+```
+
+Role data looks like the following in JSON:
+
+```json
+{
+ "name": "test",
+ "default_attributes": { },
+ "override_attributes": { },
+ "json_class": "Chef::Role",
+ "description": "This is just a test role, no big deal.",
+ "chef_type": "role",
+ "run_list": [ "recipe[test]" ]
+}
+```
+
+and like the following in the Ruby DSL:
+
+```ruby
+name 'test'
+description 'This is just a test role, no big deal.'
+run_list 'recipe[test]'
+```
+
+and finally, JSON data passed to chef-solo:
+
+```ruby
+{ 'run_list': 'role[test]' }
+```
+
+## Environments
+
+{{< readfile file="content/reusable/md/chef_solo_environments.md" >}}
+
+## chef-solo (executable)
+
+See [chef-solo (executable)](/features/chef_solo/ctl_chef_solo/) for complete CTL
+documentation.
diff --git a/content/features/chef_solo/config_rb_solo.md b/content/features/chef_solo/config_rb_solo.md
new file mode 100644
index 0000000..68a5dec
--- /dev/null
+++ b/content/features/chef_solo/config_rb_solo.md
@@ -0,0 +1,171 @@
++++
+title = "solo.rb"
+draft = false
+
+[menu]
+ [menu.features]
+ title = "solo.rb"
+ identifier = "features/chef_solo/config_rb_solo.md solo.rb Configuration"
+ parent = "features/chef_solo"
+ weight = 30
++++
+
+A solo.rb file is used to specify the configuration details for
+chef-solo.
+
+- This file is loaded every time this executable is run
+- The default location in which chef-solo expects to find this file is `/etc/chef/solo.rb`; use the `--config` option from the command line to change this location
+- This file isn't created by default
+- When a `solo.rb` file is present in this directory, the settings contained within that file will override the default configuration settings
+
+## Settings
+
+This configuration file has the following settings:
+
+`add_formatter`
+
+: A 3rd-party formatter. (See [nyan-cat](https://github.com/andreacampi/nyan-cat-chef-formatter) for an example of a 3rd-party formatter.) Each formatter requires its own entry.
+
+`checksum_path`
+
+: The location in which checksum files are stored. These are used to validate individual cookbook files, such as recipes. The checksum itself is stored in the Chef Infra Server database and is then compared to a file in the checksum path that has a filename identical to the checksum.
+
+`cookbook_path`
+
+: The Chef Infra Client sub-directory for cookbooks. This value can be a string or an array of file system locations, processed in the specified order. The last cookbook is considered to override local modifications.
+
+`data_bag_path`
+
+: The location from which a data bag is loaded. Default value: `/var/chef/data_bags`.
+
+`environment`
+
+: The name of the environment.
+
+`environment_path`
+
+: The path to the environment. Default value: `/var/chef/environments`.
+
+`file_backup_path`
+
+: The location in which backup files are stored. If this value is empty, backup files are stored in the directory of the target file. Default value: `/var/chef/backup`.
+
+`file_cache_path`
+
+: The location in which cookbooks (and other transient data) files are stored when they're synchronized. This value can also be used in recipes to download files with the **remote_file** resource.
+
+`json_attribs`
+
+: The path to a file that contains JSON data.
+
+`lockfile`
+
+: The location of the Chef Infra Client lock file. This value is typically platform-dependent, so should be a location defined by `file_cache_path`. The default location of a lock file shouldn't on an NF mount. Default value: a location defined by `file_cache_path`.
+
+`log_level`
+
+: The level of logging to be stored in a log file. Possible levels: `:auto` (default), `debug`, `info`, `warn`, `error`, or `fatal`.
+
+`log_location`
+
+: The location of the log file. Default value: `STDOUT`.
+
+`minimal_ohai`
+
+: Run the Ohai plugins for name detection and resource/provider selection and no other Ohai plugins. Set to `true` during integration testing to speed up test cycles.
+
+`node_name`
+
+: The unique identifier of the node.
+
+`recipe_url`
+
+: The URL location from which a remote cookbook tar.gz is to be downloaded.
+
+`rest_timeout`
+
+: The time (in seconds) after which an HTTP REST request is to time out. Default value: `300`.
+
+`role_path`
+
+: The location in which role files are located. Default value: `/var/chef/roles`.
+
+`run_lock_timeout`
+
+: The amount of time (in seconds) to wait for a Chef Infra Client lock file to be deleted. A Chef Infra Client run won't start when a lock file is present. If a lock file isn't deleted before this time expires, the pending Chef Infra Client run will exit. Default value: not set (indefinite). Set to `0` to cause a second Chef Infra Client to exit immediately.
+
+`sandbox_path`
+
+: The location in which cookbook files are stored (temporarily) during upload.
+
+`solo`
+
+: Run Chef Infra Client in chef-solo mode. This setting determines if Chef Infra Client is to attempt to communicate with Chef Infra Server. Default value: `false`.
+
+`syntax_check_cache_path`
+
+: All files in a cookbook must contain valid Ruby syntax. Use this setting to specify the location in which knife caches information about files that have been checked for valid Ruby syntax.
+
+`umask`
+
+: The file mode creation mask, or umask. Default value: `0022`.
+
+`verbose_logging`
+
+: Set the log level. Options: `true`, `nil`, and `false`. When this is set to `false`, notifications about individual resources being processed are suppressed (and are output at the `:info` logging level). Setting this to `false` can be useful when a Chef Infra Client is run as a daemon. Default value: `nil`.
+
+## Examples
+
+### Using Chef Automate Data Collector
+
+This example solo.rb file uses the `data_collector` settings to send data to an available Chef Automate system. Since Chef Automate generates a self-signed SSL certificate by default, you will need to add the certificate (located under `/var/opt/delivery/nginx/` on the Chef Automate server) to your `trusted_certs_dir` directory, as seen in this example:
+
+```ruby
+chef_server_url "https://localhost:8989"
+log_location STDOUT
+node_name "YOUR_NODES_FQDN"
+trusted_certs_dir "/etc/chef/trusted_certs"
+
+data_collector.server_url "https://YOUR_AUTOMATE_FQDN/data-collector/v0"
+data_collector.mode :both
+data_collector.token = "YOURTOKEN"
+```
+
+You can run it like this
+
+```ruby
+chef-solo -c solo.rb
+```
+
+### All Options
+
+A sample solo.rb file that contains all possible settings (listed alphabetically):
+
+```ruby
+add_formatter :nyan
+add_formatter :foo
+add_formatter :bar
+checksum_path '/var/chef/checksums'
+cookbook_path [
+ '/var/chef/cookbooks',
+ '/var/chef/site-cookbooks'
+ ]
+data_bag_path '/var/chef/data_bags'
+environment 'production'
+environment_path '/var/chef/environments'
+file_backup_path '/var/chef/backup'
+file_cache_path '/var/chef/cache'
+json_attribs nil
+lockfile nil
+log_level :info
+log_location STDOUT
+node_name 'mynode.example.com'
+recipe_url 'http://path/to/remote/cookbook'
+rest_timeout 300
+role_path '/var/chef/roles'
+sandbox_path 'path_to_folder'
+solo false
+syntax_check_cache_path
+umask 0022
+verbose_logging nil
+```
diff --git a/content/features/chef_solo/ctl_chef_solo.md b/content/features/chef_solo/ctl_chef_solo.md
new file mode 100644
index 0000000..337506e
--- /dev/null
+++ b/content/features/chef_solo/ctl_chef_solo.md
@@ -0,0 +1,181 @@
++++
+title = "chef-solo (executable)"
+draft = false
+
+[menu]
+ [menu.features]
+ title = "chef-solo (executable)"
+ identifier = "features/chef_solo/ctl_chef_solo.md chef-solo Commands"
+ parent = "features/chef_solo"
+ weight = 20
++++
+
+{{< readfile file="content/reusable/md/chef_solo_summary.md" >}}
+
+## Options
+
+This command has the following syntax:
+
+```bash
+chef-solo OPTION VALUE OPTION VALUE ...
+```
+
+This command has the following options:
+
+`-c CONFIG`, `--config CONFIG`
+
+: The configuration file to use.
+
+`-d`, `--daemonize`
+
+: Run the executable as a daemon. This option may not be used in the same command with the `--[no-]fork` option. This option is only available on machines that run in UNIX or Linux environments. For machines that are running Windows that require similar functionality, use the `chef-client::service` recipe in the `chef-client` cookbook: . This will install a Chef Infra Client service under Windows using the Windows Service Wrapper.
+
+`-E ENVIRONMENT_NAME`, `--environment ENVIRONMENT_NAME`
+
+: The name of the environment.
+
+`-f`, `--[no-]fork`
+
+: Contains Chef Infra Client runs in a secondary process with dedicated RAM. When a Chef Infra Client run is complete, the RAM is returned to the primary process. This option helps ensure that a Chef Infra Client uses a steady amount of RAM over time because the primary process doesn't run recipes. This option also helps prevent memory leaks such as those that can be introduced by the code contained within a poorly designed cookbook. Use `--no-fork` to disable running Chef Infra Client in fork node. Default value: `--fork`. This option may not be used in the same command with the `--daemonize` and `--interval` options.
+
+`-F FORMAT`, `--format FORMAT`
+
+: {{< readfile file="content/reusable/md/workstation/ctl_chef_client_options_format.md" >}}
+
+`--force-formatter`
+
+: Show formatter output instead of logger output.
+
+`--force-logger`
+
+: Show logger output instead of formatter output.
+
+`-g GROUP`, `--group GROUP`
+
+: The name of the group that owns a process. This is required when starting any executable as a daemon.
+
+`-h`, `--help`
+
+: Show help for the command.
+
+`-i SECONDS`, `--interval SECONDS`
+
+: The frequency (in seconds) at which Chef Infra Client runs. When running Chef Infra Client at intervals, apply `--splay` and `--interval` values before a Chef Infra Client run. This option may not be used in the same command with the `--[no-]fork` option.
+
+`-j PATH`, `--json-attributes PATH`
+
+: The path to a file that contains JSON data.
+
+ {{< readfile file="content/reusable/md/node_ctl_run_list.md" spaces=4 >}}
+
+ {{< warning >}}
+
+ {{< readfile file="content/reusable/md/node_ctl_attribute.md">}}
+
+ {{< /warning >}}
+
+`-l LEVEL`, `--log_level LEVEL`
+
+: The level of logging to be stored in a log file. Possible levels: `auto` (default), `debug`, `error`, `fatal`, `info`, `trace`, or `warn`. Default value: `warn` (when a terminal is available) or `info` (when a terminal isn't available).
+
+`-L LOGLOCATION`, `--logfile c`
+
+: The location of the log file. This is recommended when starting any executable as a daemon.
+
+`--legacy-mode`
+
+: Cause Chef Infra Client to use the original chef-solo mode instead of chef local mode. This isn't recommended. **Removed in Chef Infra Client 14.**
+
+`--minimal-ohai`
+
+: Run the Ohai plugins for name detection and resource/provider selection and no other Ohai plugins. Set to `true` during integration testing to speed up test cycles.
+
+`--[no-]color`
+
+: View colored output. Default setting: `--color`.
+
+`-N NODE_NAME`, `--node-name NODE_NAME`
+
+: The unique identifier of the node.
+
+`-o RUN_LIST_ITEM`, `--override-runlist RUN_LIST_ITEM`
+
+: Replace the current run-list with the specified items.
+
+`-r RECIPE_URL`, `--recipe-url RECIPE_URL`
+
+: The URL of the remote cookbook `tar.gz` file that you want to download.
+
+ In Chef Infra Client 14, the short `-r` form will be removed, as it conflicts with the ability to specify a run list.
+
+`--run-lock-timeout SECONDS`
+
+: The amount of time (in seconds) to wait for a Chef Infra Client lock file to be deleted. Default value: not set (indefinite). Set to `0` to cause a second Chef Infra Client to exit immediately.
+
+`-s SECONDS`, `--splay SECONDS`
+
+: A random number between zero and `splay` that's added to `interval`. Use splay to help balance the load on Chef Infra Server by ensuring that many Chef Infra Client runs aren't occurring at the same interval. When running Chef Infra Client at intervals, apply `--splay` and `--interval` values before a Chef Infra Client run.
+
+`-u USER`, `--user USER`
+
+: The user that owns a process. This is required when starting any executable as a daemon.
+
+`-v`, `--version`
+
+: The Chef Infra Client version.
+
+`-W`, `--why-run`
+
+: Run the executable in why-run mode, which is a type of Chef Infra Client run that does everything except modify the system. Use why-run mode to understand the decisions that Chef Infra Client makes during a run and to learn more about the current and proposed state of the system.
+
+## Run as Non-root User
+
+{{< warning >}}
+
+This configuration for the `chef` user provides root-level access through Chef script files that call system commands with `sudo` privileges.
+
+Use an alternative approach if your security profile forbids the `chef` user from having built-in root level access.
+
+{{< /warning >}}
+
+chef-solo may be run as a non-root user. For example, you can update the `sudoers` file:
+
+```ruby
+# chef-solo privilege specification
+chef ALL=(ALL) NOPASSWD: /usr/bin/chef-solo
+```
+
+where `chef` is the name of the non-root user. This would allow chef-solo to run any command on the node without requiring a password.
+
+## Examples
+
+### Run chef-solo using solo.rb settings
+
+```bash
+chef-solo -c ~/chef/solo.rb
+```
+
+### Use a URL
+
+```bash
+chef-solo -c ~/solo.rb -j ~/node.json -r http://www.example.com/chef-solo.tar.gz
+```
+
+The tar.gz is archived into the `file_cache_path`, and then extracted to
+`cookbooks_path`.
+
+### Use a directory
+
+```bash
+chef-solo -c ~/solo.rb -j ~/node.json
+```
+
+chef-solo will look in the `solo.rb` file to determine the directory in which cookbooks are located.
+
+### Use a URL for cookbook and JSON data
+
+```bash
+chef-solo -c ~/solo.rb -j http://www.example.com/node.json --recipe-url http://www.example.com/chef-solo.tar.gz
+```
+
+where `--recipe-url` corresponds to `recipe_url` and `-j` corresponds to `json_attribs`, both of which are [configuration options](config_rb_solo) in `solo.rb`.
diff --git a/content/features/handlers.md b/content/features/handlers.md
new file mode 100644
index 0000000..7751322
--- /dev/null
+++ b/content/features/handlers.md
@@ -0,0 +1,547 @@
++++
+title = "About Handlers"
+draft = false
+
+[menu]
+ [menu.features]
+ title = "Handlers"
+ identifier = "features/handlers.md Handlers"
+ parent = "features"
+ weight = 40
++++
+
+{{< readfile file="content/reusable/md/handler.md" >}}
+
+{{< readfile file="content/reusable/md/handler_types.md" >}}
+
+## Exception/Report Handlers
+
+{{< readfile file="content/reusable/md/handler_type_exception_report.md" >}}
+
+### Run from Recipes
+
+{{< readfile file="content/reusable/md/handler_type_exception_report_run_from_recipe.md" >}}
+
+### Run from client.rb
+
+A simple exception or report handler may be installed and configured at run-time. This requires editing of a node's client.rb file to add the appropriate setting and information about that handler to the client.rb or solo.rb files. Depending on the handler type, one (or more) of the following settings must be added:
+
+`exception_handlers`
+
+: A list of exception handlers that are available to Chef Infra Client during a Chef Infra Client run.
+
+`report_handlers`
+
+: A list of report handlers that are available to Chef Infra Client during a Chef Infra Client run.
+
+When this approach is used, the client.rb file must also tell Chef Infra Client how to install and run the handler. There is no default install location for handlers. The simplest way to distribute and install them is using RubyGems, though other methods such as GitHub or HTTP will also work. Once the handler is installed on the system, enable it in the client.rb file by requiring it. After the handler is installed, it may require additional configuration. This will vary from handler to handler. If a handler is a simple handler, it may only require the creation of a new instance. For example, if a handler named `MyOrg::EmailMe` is hardcoded for all of the values required to send email, a new instance is required. And then the custom handler must be associated with each of the handler types for which it will run.
+
+For example:
+
+```ruby
+require '/var/chef/handlers/email_me' # the installation path
+
+email_handler = MyOrg::EmailMe.new # a simple handler
+
+start_handlers << email_handler # run at the start of the run
+report_handlers << email_handler # run at the end of a successful run
+exception_handlers << email_handler # run at the end of a failed run
+```
+
+## Start Handlers
+
+{{< readfile file="content/reusable/md/handler_type_start.md" >}}
+
+### Run from Recipes
+
+{{< readfile file="content/reusable/md/handler_type_start_run_from_recipe.md" >}}
+
+### Run from client.rb
+
+A start handler can be configured in the client.rb file by adding the following setting:
+
+
+
+
+
+
+
+
+
+
+
+start_handlers |
+A list of start handlers that are available to Chef Infra Client at the start of a Chef Infra Client run. |
+
+
+
+
+For example, the Reporting start handler adds the following code to the
+top of the client.rb file:
+
+```ruby
+begin
+ require 'chef_reporting'
+ start_handlers << Chef::Reporting::StartHandler.new()
+rescue LoadError
+ Chef::Log.warn 'Failed to load #{lib}. This should be resolved after a chef run.'
+end
+```
+
+This ensures that when a Chef Infra Client run begins the `chef_reporting` event handler is enabled. The `chef_reporting` event handler is part of a gem named `chef-reporting`. The **chef_gem** resource is used to install this gem:
+
+```ruby
+chef_gem 'chef-reporting' do
+ action :install
+end
+```
+
+## Event Handlers
+
+{{< readfile file="content/reusable/md/dsl_handler_summary.md" >}}
+
+### on Method
+
+{{< readfile file="content/reusable/md/dsl_handler_method_on.md" >}}
+
+### Event types
+
+{{< readfile file="content/reusable/md/dsl_handler_event_types.md" >}}
+
+### Examples
+
+The following examples show ways to use the Handler DSL.
+
+#### Send Email
+
+{{< readfile file="content/reusable/md/dsl_handler_slide_send_email.md" >}}
+
+##### Define How Email is Sent
+
+{{< readfile file="content/reusable/md/dsl_handler_slide_send_email_library.md" >}}
+
+##### Add the Handler
+
+{{< readfile file="content/reusable/md/dsl_handler_slide_send_email_handler.md" >}}
+
+##### Test the Handler
+
+{{< readfile file="content/reusable/md/dsl_handler_slide_send_email_test.md" >}}
+
+#### etcd Locks
+
+{{< readfile file="content/reusable/md/dsl_handler_example_etcd_lock.md" >}}
+
+#### HipChat Notifications
+
+{{< readfile file="content/reusable/md/dsl_handler_example_hipchat.md" >}}
+
+## Handlers and Cookbooks
+
+The following cookbooks can be used to load handlers during a Chef InfraClient run.
+
+### chef_handler
+
+Exception and report handlers can be distributed using the **chef_handler** resource. This resource is included with Chef 14 and above. It can be used to enable custom handlers from within recipes and to include product-specific handlers from cookbooks.
+
+See the [chef_handler Resource]({{< relref "/resources/bundled/chef_handler">}}) documentation for more information.
+
+### Chef Infra Client
+
+Start handlers can be distributed using the **chef-client** cookbook, which will install the handler on the target node during the initial configuration of the node. This ensures that the start handler is always present on the node so that it's available to Chef Infra Client at the start of every run.
+
+## Custom Handlers
+
+A custom handler can be created to support any situation. The easiest way to build a custom handler:
+
+1. Download the **chef_handler** cookbook
+2. Create a custom handler
+3. Write a recipe using the **chef_handler** resource
+4. Add that recipe to a node's run-list, often as the first recipe in
+ that run-list
+
+### Syntax
+
+The syntax for a handler can vary depending on what the situations the handler is being asked to track, for example the handler type being used. All custom exception and report handlers are defined using Ruby and must be a subclass of the `Chef::Handler` class.
+
+```ruby
+require 'chef/log'
+
+module ModuleName
+ class HandlerName < Chef::Handler
+ def report
+ # Ruby code goes here
+ end
+ end
+end
+```
+
+where:
+
+- `require` ensures that the logging functionality of Chef Infra Client is available to the handler
+- `ModuleName` is the name of the module as it exists within the `Chef` library
+- `HandlerName` is the name of the handler as it's used in a recipe
+- `report` is an interface that's used to define the custom handler
+
+For example, the following shows a custom handler that sends an email that contains the exception data when a Chef Infra Client run fails:
+
+```ruby
+require 'net/smtp'
+
+module OrgName
+ class SendEmail < Chef::Handler
+ def report
+ if run_status.failed?
+ message = "From: sender_name \n"
+ message << "To: recipient_address \n"
+ message << "Subject: chef-client Run Failed\n"
+ message << "Date: #{Time.now.rfc2822}\n\n"
+ message << "Chef run failed on #{node.name}\n"
+ message << "#{run_status.formatted_exception}\n"
+ message << Array(backtrace).join('\n')
+ Net::SMTP.start('your.smtp.server', 25) do |smtp|
+ smtp.send_message message, 'sender@example', 'recipient@example'
+ end
+ end
+ end
+ end
+end
+```
+
+and then is used in a recipe like:
+
+```ruby
+send_email 'blah' do
+ # recipe code
+end
+```
+
+### report Interface
+
+The `report` interface is used to define how a handler will behave and is a required part of any custom handler. The syntax for the `report` interface is as follows:
+
+```ruby
+def report
+ # Ruby code
+end
+```
+
+The Ruby code used to define a custom handler will vary significantly from handler to handler. Chef Infra Client includes two default handlers: `error_report` and `json_file`. Their use of the `report` interface is shown below.
+
+The [error_report](https://github.com/chef/chef/blob/main/lib/chef/handler/error_report.rb) handler:
+
+```ruby
+require 'chef/handler'
+require 'chef/resource/directory'
+
+class Chef
+ class Handler
+ class ErrorReport < ::Chef::Handler
+ def report
+ Chef::FileCache.store('failed-run-data.json', Chef::JSONCompat.to_json_pretty(data), 0640)
+ Chef::Log.fatal("Saving node information to #{Chef::FileCache.load('failed-run-data.json', false)}")
+ end
+ end
+ end
+end
+```
+
+The [json_file](https://github.com/chef/chef/blob/main/lib/chef/handler/json_file.rb) handler:
+
+```ruby
+require 'chef/handler'
+require 'chef/resource/directory'
+
+class Chef
+ class Handler
+ class JsonFile < ::Chef::Handler
+ attr_reader :config
+ def initialize(config = {})
+ @config = config
+ @config[:path] ||= '/var/chef/reports'
+ @config
+ end
+
+ def report
+ if exception
+ Chef::Log.error('Creating JSON exception report')
+ else
+ Chef::Log.info('Creating JSON run report')
+ end
+ build_report_dir
+ savetime = Time.now.strftime('%Y%m%d%H%M%S')
+ File.open(File.join(config[:path], 'chef-run-report-#{savetime}.json'), 'w') do |file|
+ run_data = data
+ run_data[:start_time] = run_data[:start_time].to_s
+ run_data[:end_time] = run_data[:end_time].to_s
+ file.puts Chef::JSONCompat.to_json_pretty(run_data)
+ end
+ end
+
+ def build_report_dir
+ unless File.exist?(config[:path])
+ FileUtils.mkdir_p(config[:path])
+ File.chmod(00700, config[:path])
+ end
+ end
+ end
+ end
+end
+```
+
+### Optional Interfaces
+
+The following interfaces may be used in a handler in the same way as the `report` interface to override the default handler behavior in Chef Infra Client. That said, the following interfaces aren't typically used in a handler and, for the most part, are completely unnecessary for a handler to work properly and/or as desired.
+
+#### data
+
+The `data` method is used to return the Hash representation of the `run_status` object. For example:
+
+```ruby
+def data
+ @run_status.to_hash
+end
+```
+
+#### run_report_safely
+
+The `run_report_safely` method is used to run the report handler, rescuing and logging errors that may arise as the handler runs and ensuring that all handlers get a chance to run during a Chef Infra Client run (even if some handlers fail during that run). In general, this method should never be used as an interface in a custom handler unless this default behavior simply must be overridden.
+
+```ruby
+def run_report_safely(run_status)
+ run_report_unsafe(run_status)
+rescue Exception => e
+ Chef::Log.error('Report handler #{self.class.name} raised #{e.inspect}')
+ Array(e.backtrace).each { |line| Chef::Log.error(line) }
+ensure
+ @run_status = nil
+end
+```
+
+#### run_report_unsafe
+
+The `run_report_unsafe` method is used to run the report handler without any error handling. This method should never be used directly in any handler, except during testing of that handler. For example:
+
+```ruby
+def run_report_unsafe(run_status)
+ @run_status = run_status
+ report
+end
+```
+
+### run_status Object
+
+The `run_status` object is initialized by Chef Infra Client before the `report` interface is run for any handler. The `run_status` object keeps track of the status of a Chef Infra Client run and will contain some (or all) of the following properties:
+
+`all_resources`
+
+: A list of all resources that are included in the `resource_collection` property for the current Chef Infra Client run.
+
+`backtrace`
+
+: A backtrace associated with the uncaught exception data that caused a Chef Infra Client run to fail, if present; `nil` for a successful Chef Infra Client run.
+
+`elapsed_time`
+
+: The amount of time between the start (`start_time`) and end (`end_time`) of a Chef Infra Client run.
+
+`end_time`
+
+: The time at which a Chef Infra Client run ended.
+
+`exception`
+
+: The uncaught exception data which caused a Chef Infra Client run to fail; `nil` for a successful Chef Infra Client run.
+
+`failed?`
+
+: Show that a Chef Infra Client run has failed when uncaught exceptions were raised during a Chef Infra Client run. An exception handler runs when the `failed?` indicator is `true`.
+
+`node`
+
+: The node on which a Chef Infra Client run occurred.
+
+`run_context`
+
+: An instance of the `Chef::RunContext` object; used by Chef Infra Client to track the context of the run; provides access to the `cookbook_collection`, `resource_collection`, and `definitions` properties.
+
+`start_time`
+
+: The time at which a Chef Infra Client run started.
+
+`success?`
+
+: Show that a Chef Infra Client run succeeded when uncaught exceptions weren't raised during a Chef Infra Client run. A report handler runs when the `success?` indicator is `true`.
+
+`updated_resources`
+
+: A list of resources that were marked as updated as a result of a Chef Infra Client run.
+
+{{< note >}}
+
+These properties aren't always available. For example, a start handler runs at the beginning of Chef Infra Client run, which means that properties like `end_time` and `elapsed_time` are still unknown and will be unavailable to the `run_status` object.
+
+{{< /note >}}
+
+## Examples
+
+The following sections show examples of handlers.
+
+### Cookbook versions
+
+Community member `juliandunn` created a custom [report handler that logs all of the cookbooks and cookbook versions](https://github.com/juliandunn/cookbook_versions_handler) that were used during a Chef Infra Client run, and then reports after the run is complete. This handler requires the **chef_handler** resource (which is available from the **chef_handler** cookbook).
+
+#### cookbook_versions.rb
+
+The following custom handler defines how cookbooks and cookbook versions that are used during a Chef Infra Client run will be compiled into a report using the `Chef::Log` class in Chef Infra Client:
+
+```ruby
+require 'chef/log'
+
+module Opscode
+ class CookbookVersionsHandler < Chef::Handler
+ def report
+ cookbooks = run_context.cookbook_collection
+ Chef::Log.info('Cookbooks and versions run: #{cookbooks.keys.map {|x| cookbooks[x].name.to_s + ' ' + cookbooks[x].version} }')
+ end
+ end
+end
+```
+
+#### default.rb
+
+The following recipe is added to the run-list for every node on which a list of cookbooks and versions will be generated as report output after every Chef Infra Client run.
+
+```ruby
+include_recipe 'chef_handler'
+
+cookbook_file "#{node['chef_handler']['handler_path']}/cookbook_versions.rb" do
+ source 'cookbook_versions.rb'
+ owner 'root'
+ group 'root'
+ mode '0755'
+ action :create
+end
+
+chef_handler 'Opscode::CookbookVersionsHandler' do
+ source "#{node['chef_handler']['handler_path']}/cookbook_versions.rb"
+ supports :report => true
+ action :enable
+end
+```
+
+This recipe will generate report output similar to the following:
+
+```ruby
+[2013-11-26T03:11:06+00:00] INFO: Chef Run complete in 0.300029878 seconds
+[2013-11-26T03:11:06+00:00] INFO: Running report handlers
+[2013-11-26T03:11:06+00:00] INFO: Cookbooks and versions run: ["chef_handler 1.1.4", "cookbook_versions_handler 1.0.0"]
+[2013-11-26T03:11:06+00:00] INFO: Report handlers complete
+```
+
+### Reporting
+
+Start handler functionality was added when Chef started building add-ons for Chef Infra Server. The Reporting add-on is designed to create reporting data based on a Chef Infra Client run. And since Reporting needs to be able to collect data for the entire Chef Infra Client run, Reporting needs to be enabled before anything else happens at the start of a Chef Infra Client run.
+
+{{< note >}}
+
+The start handler used by the Reporting add-on for Chef Infra Server is always installed using the **chef-client** cookbook.
+
+{{< /note >}}
+
+#### start_handler.rb
+
+The following code shows the start handler used by the Reporting add-in for Chef Infra Server:
+
+```ruby
+require 'chef/handler'
+require 'chef/rest'
+require 'chef/version_constraint'
+
+class Chef
+ class Reporting
+ class StartHandler < ::Chef::Handler
+ attr_reader :config
+
+ def initialize(config = {})
+ @config = config
+ end
+
+ def report
+ version_checker = Chef::VersionConstraint.new('< 11.6.0')
+ if version_checker.include?(Chef::VERSION)
+ Chef::Log.info('Enabling backported resource reporting Handler')
+ rest = Chef::REST.new(Chef::Config[:chef_server_url], @run_status.node.name, Chef::Config[:client_key])
+ resource_reporter = Chef::Reporting::ResourceReporter.new(rest)
+ @run_status.events.register(resource_reporter)
+
+ resource_reporter.run_started(@run_status)
+ else
+ Chef::Log.debug('Chef Version already has new Resource Reporter - skipping startup of backport version')
+ end
+ end
+ end
+ end
+end
+```
+
+### json_file Handler
+
+The [json_file](https://github.com/chef/chef/blob/main/lib/chef/handler/json_file.rb) handler is available from the **chef_handler** cookbook and can be used with exceptions and reports. It serializes run status data to a JSON file. This handler may be enabled in one of the following ways.
+
+By adding the following lines of Ruby code to either the client.rb file or the solo.rb file, depending on how Chef Infra Client is being run:
+
+```ruby
+require 'chef/handler/json_file'
+report_handlers << Chef::Handler::JsonFile.new(:path => '/var/chef/reports')
+exception_handlers << Chef::Handler::JsonFile.new(:path => '/var/chef/reports')
+```
+
+By using the **chef_handler** resource in a recipe, similar to the
+following:
+
+```ruby
+chef_handler 'Chef::Handler::JsonFile' do
+ source 'chef/handler/json_file'
+ arguments :path => '/var/chef/reports'
+ action :enable
+end
+```
+
+After it has run, the run status data can be loaded and inspected using Interactive Ruby (IRb):
+
+```ruby
+irb(main):002:0> require 'json' => true
+irb(main):003:0> require 'chef' => true
+irb(main):004:0> r = JSON.parse(IO.read('/var/chef/reports/chef-run-report-20110322060731.json')) => ... output truncated
+irb(main):005:0> r.keys => ['end_time', 'node', 'updated_resources', 'exception', 'all_resources', 'success', 'elapsed_time', 'start_time', 'backtrace']
+irb(main):006:0> r['elapsed_time'] => 0.00246
+```
+
+### error_report Handler
+
+The [error_report](https://github.com/chef/chef/blob/main/lib/chef/handler/error_report.rb) handler is built into Chef Infra Client and can be used for both exceptions and reports. It serializes error report data to a JSON file. This handler may be enabled in one of the following ways.
+
+By adding the following lines of Ruby code to either the client.rb file or the solo.rb file, depending on how Chef Infra Client is being run:
+
+```ruby
+require 'chef/handler/error_report'
+report_handlers << Chef::Handler::ErrorReport.new()
+exception_handlers << Chef::Handler::ErrorReport.new()
+```
+
+By using the [chef_handler](/resources/bundled/chef_handler/) resource in a recipe, similar to the following:
+
+```ruby
+chef_handler 'Chef::Handler::ErrorReport' do
+ source 'chef/handler/error_report'
+ action :enable
+end
+```
+
+### Community Handlers
+
+{{< readfile file="content/reusable/md/handler_community_handlers.md" >}}
diff --git a/content/features/ohai/_index.md b/content/features/ohai/_index.md
new file mode 100644
index 0000000..6d30a5b
--- /dev/null
+++ b/content/features/ohai/_index.md
@@ -0,0 +1,285 @@
++++
+title = "About Ohai"
+draft = false
+linkTitle = "Ohai"
+
+[menu]
+ [menu.features]
+ title = "About Ohai"
+ identifier = "features/ohai/ohai.md About Ohai"
+ parent = "features/ohai"
+ weight = 10
++++
+
+{{< readfile file="content/reusable/md/ohai_summary.md" >}}
+
+Ohai collects data for many platforms, including AIX, macOS, Linux, FreeBSD, Solaris, and any Windows operating systems.
+
+See the [Chef Infra Client release notes](https://docs.chef.io/release_notes/client/) for the latest information on Ohai.
+
+## Automatic Attributes
+
+{{< note >}}
+
+{{< readfile file="content/reusable/md/notes_see_attributes_overview.md" >}}
+
+{{< /note >}}
+
+{{< readfile file="content/reusable/md/ohai_automatic_attribute.md" >}}
+
+### Get a list of automatic attributes for a node
+
+{{< readfile file="content/reusable/md/ohai_attribute_list.md" >}}
+
+### Attributes Blocklist
+
+{{< warning >}}
+
+{{< readfile file="content/reusable/md/node_attribute_blocklist_warning.md" >}}
+
+{{< /warning >}}
+
+{{< readfile file="content/reusable/md/node_attribute_blocklist.md" >}}
+
+### Attribute Allowlist
+
+{{< warning >}}
+
+{{< readfile file="content/reusable/md/node_attribute_allowlist_warning.md" >}}
+
+{{< /warning >}}
+
+## Default Plugins
+
+The following list shows the type of plugins that are included with Ohai. See the `ohai/lib/ohai/plugins` directory in the version of Ohai installed on your system for the full list:
+
+### General Purpose Plugins
+
+```ruby
+azure.rb
+c.rb
+chef.rb
+cloud.rb
+command.rb
+cpu.rb
+digital_ocean.rb
+dmi.rb
+docker.rb
+ec2.rb
+elixir.rb
+erlang.rb
+eucalyptus.rb
+filesystem.rb
+freebsd
+gce.rb
+go.rb
+groovy.rb
+haskell.rb
+hostname.rb
+init_package.rb
+java.rb
+joyent.rb
+kernel.rb
+keys.rb
+languages.rb
+libvirt.rb
+linode.rb
+lua.rb
+mono.rb
+network.rb
+nodejs.rb
+ohai_time.rb
+ohai.rb
+memory.rb
+network.rb
+platform.rb
+openstack.rb
+os.rb
+packages.rb
+perl.rb
+php.rb
+platform.rb
+powershell.rb
+ps.rb
+python.rb
+rackspace.rb
+root_group.rb
+ruby.rb
+rust.rb
+scala.rb
+scaleway.rb
+shard.rb
+shells.rb
+softlayer.rb
+ssh_host_key.rb
+timezone.rb
+uptime.rb
+virtualbox.rb
+vmware.rb
+zpools.rb
+```
+
+### Platform Specific Plugins
+
+```ruby
+aix
+ kernel.rb
+ memory.rb
+ network.rb
+ platform.rb
+ uptime.rb
+ virtualization.rb
+bsd
+ virtualization.rb
+darwin
+ cpu.rb
+ filesystem.rb
+ hardware.rb
+ memory.rb
+ network.rb
+ platform.rb
+ system_profiler.rb
+ virtualization.rb
+dragonflybsd
+ cpu.rb
+ memory.rb
+ network.rb
+ os.rb
+ platform.rb
+freebsd
+ cpu.rb
+ memory.rb
+ network.rb
+ os.rb
+ platform.rb
+linux
+ block_device.rb
+ cpu.rb
+ filesystem.rb
+ fips.rb
+ hostnamectl.rb
+ lsb.rb
+ machineid.rb
+ mdadm.rb
+ memory.rb
+ network.rb
+ platform.rb
+ sessions.rb
+ virtualization.rb
+netbsd
+ cpu.rb
+ memory.rb
+ network.rb
+ platform.rb
+openbsd
+ cpu.rb
+ memory.rb
+ network.rb
+ platform.rb
+solaris2
+ cpu.rb
+ dmi.rb
+ filesystem.rb
+ memory.rb
+ network.rb
+ platform.rb
+ virtualization.rb
+windows
+ cpu.rb
+ drivers.rb
+ filesystem.rb
+ fips.rb
+ memory.rb
+ network.rb
+ platform.rb
+ system_enclosure.rb
+ virtualization.rb
+```
+
+## Optional Plugins
+
+Ohai ships several optional plugins that you can enable in the [client.rb configuration file](/install/config_rb_client/).
+
+ `:Grub2`
+: Information from the Linux Grub2 bootloader
+
+ `:IPC`
+: SysV IPC shmem information (New in Chef Infra Client 16)
+
+ `:Interupts`
+: Data from /proc/interrupts and /proc/irq (New in Chef Infra Client 16)
+
+ `:Lspci`
+: PCI device information on Linux hosts.
+
+ `:Lsscsi`
+: SCSI device information on Linux hosts.
+
+ `:Passwd`
+: User and Group information. This plugin can result in large node sizes if a system connects to Active Directory or LDAP.
+
+ `:Sessions`
+: Sessions data from loginctl on Linux hosts.
+
+`:Sysctl`
+
+: All sysctl values on Linux hosts.
+
+### Enabling Optional Plugins
+
+Optional plugins can be enabled in the [client.rb configuration file](/install/config_rb_client/):
+
+```ruby
+ohai.optional_plugins = [
+ :Sessions,
+ :Lspci,
+]
+```
+
+{{< note >}}
+
+The Ohai optional_plugins config array must contain an array of plugin names as Symbols not Strings.
+
+{{< /note >}}
+
+## Ohai Settings in client.rb
+
+{{< readfile file="content/reusable/md/config_rb_ohai.md" >}}
+
+{{< readfile file="content/reusable/md/config_rb_ohai_settings.md" >}}
+
+## Custom Plugins
+
+Custom Ohai plugins can be written to collect additional information from systems as necessary. See the [Ohai Custom Plugins](/extension_apis/custom_plugins/) docs for more information.
+
+## Hints
+
+Ohai hints are used to tell Ohai something about the system that it's running on that it would not be able to discover itself. An Ohai hint exists if a JSON file exists in the hint directory with the same name as the hint. For example, calling `hint?('antarctica')` in an Ohai plugin would return an empty hash if the file `antarctica.json` existed in the hints directory, and return nil if the file doesn't exist.
+
+If the hint file contains JSON content, it will be returned as a hash from the call to `hint?`.
+
+```json
+{
+ "snow": true,
+ "penguins": "many"
+}
+```
+
+```ruby
+antarctica_hint = hint?('antarctica')
+if antarctica_hint['snow']
+ "There are #{antarctica_hint['penguins']} penguins here."
+else
+ 'There is no snow here, and penguins like snow.'
+end
+```
+
+Hint files are located in the `/etc/chef/ohai/hints/` directory by default. Use the `Ohai.config[:hints_path]` setting in the [client.rb configuration file](/install/config_rb_client/) to customize this location.
+
+## `ohai` Resource
+
+Chef Infra Client includes an `ohai` resource that allows you to reload the Ohai data on a node. This allows recipes or resources that change system attributes (like a recipe that adds a user) to refer to those attributes later on during a Chef Infra Client run. See the [ohai resource](/resources/bundled/ohai) for complete usage information.
+
+## ohai Command Line Tool
+
+Ohai can be run on the command line outside of the Chef Infra Client run. See [Ohai (executable)](ctl_ohai) for more information.
diff --git a/content/features/ohai/ctl_ohai.md b/content/features/ohai/ctl_ohai.md
new file mode 100644
index 0000000..00ddc51
--- /dev/null
+++ b/content/features/ohai/ctl_ohai.md
@@ -0,0 +1,128 @@
++++
+title = "ohai (executable)"
+draft = false
+
+[menu]
+ [menu.features]
+ title = "ohai (executable)"
+ identifier = "features/ohai/ctl_ohai.md ohai Commands"
+ parent = "features/ohai"
+ weight = 20
++++
+
+
+
+`ohai` is the command-line interface for Ohai, a tool that's used to
+detect attributes on a node, and then provide these attributes to Chef
+Infra Client at the start of every Chef Infra Client run.
+
+## Options
+
+This command has the following syntax:
+
+```bash
+ohai OPTION
+```
+
+This tool has the following options:
+
+`ATTRIBUTE_NAME ATTRIBUTE NAME ...`
+
+: Use to have Ohai show only output for named attributes. To address attributes deeper in the tree, use a `/` delimiter between each level. For example: `memory/free`.
+
+`-c CONFIG`, `--config CONFIG`
+
+: The path to a configuration file to use. For example:
+ `/etc/ohai/config.rb`.
+
+`-d DIRECTORY`, `--directory DIRECTORY`
+
+: The directory in which additional Ohai plugins are located. For
+ example: `/my/extra/plugins`.
+
+`-h`, `--help`
+
+: Show help for the command.
+
+`-l LEVEL`, `--log_level LEVEL`
+
+: The level of logging to be stored in a log file.
+
+`-L LOGLOCATION`, `--logfile LOGLOCATION`
+
+: The location of the log file.
+
+`-v`, `--version`
+
+: The version of Ohai.
+
+## Examples
+
+The following examples show how to use the Ohai command-line tool:
+
+### Query for a specific attribute
+
+Pass an attribute as an argument to `ohai` to get the value of that attribute. For example:
+
+```bash
+ohai os
+```
+
+This fetches the value of Chef Infra's node data at `node['os']` and returns something like:
+
+```json
+[
+ "linux"
+]
+```
+
+To query for an attribute deeper in the node attribute tree, use a forward slash (`/`) as a delimiter between each level.
+For example, to query for free memory:
+
+```bash
+ohai memory/free
+```
+
+This returns the value of `node['memory']['free']`.
+
+### Run a plugin independently of a Chef Infra Client run
+
+An Ohai plugin can be run independently of a Chef Infra Client run.
+First, ensure that the plugin is located in the `/plugins` directory and
+then use the `-f` option when running Ohai from the command line. For
+example, a plugin named `sl_installed` may look like the following:
+
+```ruby
+Ohai.plugin(:Sl) do
+ provides "sl"
+
+ collect_data(:default) do
+ sl Mash.new
+
+ if ::File.exist?("/usr/games/sl")
+ sl[:installed] = true
+ else
+ sl[:installed] = false
+ end
+
+ # sl[:installed] = ::File.exist?("/usr/games/sl")
+
+ end
+end
+```
+
+To run that plugin from the command line, use the following command:
+
+```bash
+ohai --directory /path/to/directory sl
+```
+
+The command returns something similar to:
+
+```json
+{
+ "sl": {
+ "installed": true
+ }
+}
+```
diff --git a/content/infra_language/_index.md b/content/infra_language/_index.md
new file mode 100644
index 0000000..60a7910
--- /dev/null
+++ b/content/infra_language/_index.md
@@ -0,0 +1,27 @@
++++
+title = "About the Chef Infra Language"
+draft = false
+list_pages = true
+
+[menu]
+ [menu.infra_language]
+ title = "Language Overview"
+ identifier = "infra_language/ Language Overview"
+ parent = "infra_language"
+ weight = 10
++++
+
+{{< readfile file="content/reusable/md/infra_lang_summary.md" >}}
+
+{{< readfile file="content/reusable/md/infra_lang_ruby.md" >}}
+
+## Resources
+
+Resources are the cornerstone of the Chef Infra Language. Resources define the desired state of an object on a system. A resource can be as simple as a directory or as complex or a complete security policy. Chef Infra Client ships with over 150 resources for configuring components such as packages, files, directories, or firewalls. For more information on resources in Chef Infra Client including a complete list of those included out of the box see [Resources](/resources).
+
+## Helpers Methods
+
+The Chef Infra Language provides support for using attributes, data bags (and
+encrypted data), and search results in a recipe, as well as four helper
+methods that can be used to check for a node's platform from the recipe
+to ensure that specific actions are taken for specific platforms.
diff --git a/content/infra_language/checking_architectures.md b/content/infra_language/checking_architectures.md
new file mode 100644
index 0000000..d1fcd76
--- /dev/null
+++ b/content/infra_language/checking_architectures.md
@@ -0,0 +1,63 @@
++++
+title = "Chef Infra Language: Checking Architectures"
+linkTitle = "Checking Architectures"
+draft = false
+
+[menu]
+ [menu.infra_language]
+ title = "Checking Architectures"
+ identifier = "infra_language/checking_architectures.md Checking Architectures"
+ parent = "infra_language"
++++
+
+
+
+Chef Infra Client 15.5 and later includes helper methods for checking the processor architecture of systems. These methods can be used in attribute files, recipes, and resources.
+
+## _32_bit?
+
+Determines if the current architecture is 32-bit.
+
+## _64_bit?
+
+Determines if the current architecture is 64-bit.
+
+## arm?
+
+Determines if the current architecture is arm.
+
+## armhf?
+
+Determines if the current architecture is 32-bit ARM hard float.
+
+## i386?
+
+Determines if the current architecture is i386.
+
+## intel?
+
+Determines if the current architecture is Intel.
+
+## powerpc?
+
+Determines if the current architecture is PowerPC.
+
+## ppc64?
+
+Determines if the current architecture is PowerPC 64bit Big Endian.
+
+## ppc64le?
+
+Determines if the current architecture is PowerPC 64bit Little Endian.
+
+## s390?
+
+Determines if the current architecture is s390.
+
+## s390x?
+
+Determines if the current architecture is s390x.
+
+## sparc?
+
+Determines if the current architecture is SPARC.
diff --git a/content/infra_language/checking_clouds.md b/content/infra_language/checking_clouds.md
new file mode 100644
index 0000000..7927e1d
--- /dev/null
+++ b/content/infra_language/checking_clouds.md
@@ -0,0 +1,53 @@
++++
+title = "Chef Infra Language: Checking Clouds"
+linkTitle = "Checking Clouds"
+draft = false
+
+[menu]
+ [menu.infra_language]
+ title = "Checking Clouds"
+ identifier = "infra_language/checking_clouds.md Checking Clouds"
+ parent = "infra_language"
++++
+
+Chef Infra Client 15.8 and later includes helper methods for checking if a node is running in a public or private cloud.
+
+## cloud?
+
+Determine if the current node is running a known public or private cloud.
+
+## ec2?
+
+Determine if the current node is running in AWS EC2.
+
+## gce?
+
+Determine if the current node is running in Google Compute Engine (GCE)
+
+## rackspace?
+
+Determine if the current node is running in Rackspace.
+
+## eucalyptus?
+
+Determine if the current node is running in Eucalyptus.
+
+## linode?
+
+Determine if the current node is running in Linode.
+
+## openstack?
+
+Determine if the current node is running in OpenStack.
+
+## azure?
+
+Determine if the current node is running in Microsoft Azure.
+
+## digital_ocean?
+
+Determine if the current node is running in DigitalOcean.
+
+## softlayer?
+
+Determine if the current node is running in SoftLayer (IBM Cloud).
diff --git a/content/infra_language/checking_hypervisors.md b/content/infra_language/checking_hypervisors.md
new file mode 100644
index 0000000..24b105f
--- /dev/null
+++ b/content/infra_language/checking_hypervisors.md
@@ -0,0 +1,100 @@
++++
+title = "Chef Infra Language: Checking Hypervisors"
+draft = false
+
+[menu]
+ [menu.infra_language]
+ title = "Checking Hypervisors"
+ identifier = "infra_language/checking_hypervisors.md Checking Hypervisors"
+ parent = "infra_language"
++++
+
+Chef Infra Client 15.8 and later includes helper methods for checking if a hypervisor host or guest.
+
+## guest?
+
+Determine if the current node is running under any virtualization environment.
+
+## hypervisor?
+
+Determine if the current node supports running guests under any virtualization environment.
+
+## physical?
+
+Determine if the current node isn't running under any virtualization environment (bare-metal or hypervisor on metal).
+
+## hyperv?
+
+Determine if the current node is a Hyper-V guest.
+
+## kvm?
+
+Determine if the current node is a KVM guest.
+
+## kvm_host?
+
+Determine if the current node is a KVM host.
+
+## lxc?
+
+Determine if the current node is a LXC-based container.
+
+## lxc_host?
+
+Determine if the current node is a LXC host.
+
+## parallels?
+
+Determine if the current node is running under Parallels Desktop.
+
+## parallels_host?
+
+Determine if the current node is a Parallels Desktop host.
+
+## vbox?
+
+Determine if the current node is a VirtualBox guest.
+
+## vbox_host?
+
+Determine if the current node is a VirtualBox host.
+
+## vmware?
+
+Determine if the current node is a VMWare guest.
+
+## vmware_host?
+
+Determine if the current node is VMware host.
+
+## vmware_desktop?
+
+Determine if the current node is a guest on VMware desktop products (Fusion, Player, Workstation).
+
+## vmware_vsphere?
+
+Determine if the current node is a guest on VMware vSphere (aka ESXi).
+
+## openvz?
+
+Determine if the current node is an openvz guest.
+
+## openvz_host?
+
+Determine if the current node is an openvz host.
+
+## vagrant?
+
+Determine if the current node is running as a vagrant guest.
+
+## vagrant_key?
+
+Check if the `vagrant` key exists on the +node+ object. Note: This key is no longer populated by vagrant, but it's kept around for legacy purposes.
+
+## vagrant_domain?
+
+Check if `vagrantup.com` is included in the node's domain.
+
+## vagrant_user?
+
+Check if the system contains a `vagrant` user.
diff --git a/content/infra_language/checking_platforms.md b/content/infra_language/checking_platforms.md
new file mode 100644
index 0000000..71b669c
--- /dev/null
+++ b/content/infra_language/checking_platforms.md
@@ -0,0 +1,468 @@
++++
+title = "Chef Infra Language: Checking Platforms"
+draft = false
+
+[menu]
+ [menu.infra_language]
+ title = "Checking Platforms"
+ identifier = "infra_language/checking_platforms.md Checking Platforms"
+ parent = "infra_language"
++++
+
+
+
+## platform?
+
+Use the `platform?` helper method to ensure that certain actions are run for specific platforms. The `platform?` method will return true if one of the listed parameters matches the `node['platform']` attribute that's detected by [Ohai](/features/ohai) during every Chef Infra Client run.
+
+The syntax for the `platform?` method is as follows:
+
+```ruby
+platform?('parameter', 'parameter')
+```
+
+where:
+
+- `parameter` is a comma-separated list, each specifying a platform, such as Red Hat, CentOS, or Fedora
+- `platform?` method is typically used with an `if`, `elsif`, or `case` statement that contains Ruby code that's specific for the platform, if detected
+
+### Platform values
+
+
+
+
+
+
+
+
+
+
+
+
+
+aix |
+IBM AIX |
+
+
+alibabalinux |
+Alibaba Cloud Linux |
+
+
+almalinux |
+AlmaLinux |
+
+
+amazon |
+Amazon Linux |
+
+
+arch |
+Arch Linux |
+
+
+clearos |
+ClearOS |
+
+
+cloudlinux |
+Cloud Linux OS |
+
+
+cumulus |
+NVIDIA Cumulus Linux |
+
+
+debian |
+Debian GNU/Linux |
+
+
+fedora |
+Fedora |
+
+
+freebsd |
+FreeBSD |
+
+
+gentoo |
+Gentoo Linux |
+
+
+linuxmint |
+Linux Mint |
+
+
+mac_os_x |
+macOS |
+
+
+netbsd |
+NetBSD |
+
+
+openbsd |
+OpenBSD |
+
+
+openindiana |
+OpenIndiana |
+
+
+opensuseleap |
+openSUSE leap |
+
+
+pidora |
+Pidora |
+
+
+raspbian |
+Raspberry Pi OS |
+
+
+redhat |
+Red Hat Enterprise Linux |
+
+
+rocky |
+Rocky Linux |
+
+
+sangoma |
+Sangoma Linux |
+
+
+scientific |
+Scientific Linux |
+
+
+solaris2 |
+Oracle Solaris |
+
+
+suse |
+SUSE Linux Enterprise Server. |
+
+
+ubuntu |
+Ubuntu Linux |
+
+
+virtuozzo |
+Virtuozzo |
+
+
+windows |
+Windows |
+
+
+xenserver |
+Citrix XenServer |
+
+
+
+
+### Examples
+
+#### Installing the cron package on Debian systems
+
+```ruby
+package 'cron' if platform?('debian')
+```
+
+#### Deleting a file on Red Hat and Debian systems
+
+```ruby
+if platform?('redhat', 'debian')
+ file '/etc/some_config' do
+ action :remove
+ end
+end
+```
+
+#### Installing the correct Firefox package
+
+The following example shows how an if statement can be used with the
+`platform?` method in the Chef Infra Language to run code specific to Microsoft
+Windows. The code is defined using the **ruby_block** resource:
+
+```ruby
+if platform?('windows')
+ chocolatey_package 'firefox'
+else
+ package 'firefox'
+end
+```
+
+## platform_family?
+
+Use the `platform_family?` method to ensure that certain actions are run for specific platform families. The `platform_family?` method will return true if one of the listed parameters matches the `node['platform_family']` attribute that are detected by [Ohai](/features/ohai) during every Chef Infra Client run.
+
+The syntax for the `platform_family?` method is as follows:
+
+```ruby
+platform_family?('parameter', 'parameter')
+```
+
+where:
+
+- `'parameter'` is a comma-separated list, each specifying a platform family, such as Debian, or Red Hat Enterprise Linux
+- `platform_family?` method is typically used with an `if`, `elsif`, or `case` statement that contains Ruby code that's specific for the platform family, if detected
+
+### platform_family Values
+
+
+
+
+
+
+
+
+
+
+
+aix |
+aix platform. |
+
+
+alpine |
+alpine platform. |
+
+
+amazon |
+amazon platform. |
+
+
+arch |
+arch, manjaro, and antergos platforms. |
+
+
+debian |
+debian, ubuntu, linuxmint, raspbian, cumulus, kali, sangoma, and pop platforms. |
+
+
+fedora |
+fedora, pidora, and arista_eos platforms |
+
+
+freebsd |
+freebsd platform |
+
+
+gentoo |
+gentoo platform |
+
+
+mac_os_x |
+mac_os_x platform |
+
+
+netbsd |
+netbsd platform |
+
+
+openbsd |
+openbsd platform |
+
+
+openindiana |
+openindiana platform |
+
+
+rhel |
+redhat, centos, oracle, almalinux, rocky, scientific, xenserver, clearos, bigip, parallels, xcp, virtuozzo, alibabalinux, and ibm_powerkvm platforms |
+
+
+solaris2 |
+solaris2 platform |
+
+
+suse |
+opensuse_leap, suse, and sled platforms |
+
+
+windows |
+windows platform |
+
+
+
+
+### Examples
+
+For example:
+
+```ruby
+platform_family?('gentoo')
+```
+
+or:
+
+```ruby
+platform_family?('slackware', 'suse', 'arch')
+```
+
+#### Use a Specific Binary For a Specific Platform
+
+The following is an example of using the `platform_family?` method in
+the Chef Infra Language to create a variable that can be used with other
+resources in the same recipe. In this example, `platform_family?` is
+being used to ensure that a specific binary is used for a specific
+platform before using the **remote_file** resource to download a file
+from a remote location, and then using the **execute** resource to
+install that file by running a command.
+
+```ruby
+if platform_family?('rhel')
+ pip_binary = '/usr/bin/pip'
+else
+ pip_binary = '/usr/local/bin/pip'
+end
+
+remote_file "#{Chef::Config[:file_cache_path]}/distribute_setup.py" do
+ source 'http://python-distribute.org/distribute_setup.py'
+ mode '0755'
+ not_if { ::File.exist?(pip_binary) }
+end
+
+execute 'install-pip' do
+ cwd Chef::Config[:file_cache_path]
+ command <<-EOF
+ # command for installing Python goes here
+ EOF
+ not_if { ::File.exist?(pip_binary) }
+end
+```
+
+where a command for installing Python might look something like:
+
+```ruby
+#{node['python']['binary']} distribute_setup.py
+#{::File.dirname(pip_binary)}/easy_install pip
+```
+
+## value_for_platform
+
+Use the `value_for_platform` method in a recipe to select a value based on the `node['platform']` and `node['platform_version']` attributes. These values are detected by Ohai during every Chef Infra Client run.
+
+The syntax for the `value_for_platform` method is as follows:
+
+```ruby
+value_for_platform( ['platform', ...] => { 'version' => 'value' } )
+```
+
+where:
+
+- `'platform', ...` is a comma-separated list of platforms, such as Red Hat, openSUSE, or Fedora
+- `version` specifies the version of that platform
+- Version constraints---`>`, `<`, `>=`, `<=`, `~>`---may be used with `version`; an exception is raised if two version constraints match; an exact match will always take precedence over a match made from a version constraint
+- `value` specifies the value that will be used if the node's platform matches the `value_for_platform` method
+
+When each value only has a single platform, use the following syntax:
+
+```ruby
+value_for_platform(
+ 'platform' => { 'version' => 'value' },
+ 'platform' => { 'version' => 'value' },
+ 'platform' => 'value'
+)
+```
+
+When each value has more than one platform, the syntax changes to:
+
+```ruby
+value_for_platform(
+ ['platform', 'platform', ... ] => {
+ 'version' => 'value'
+ },
+)
+```
+
+### Operators
+
+{{< readfile file="content/reusable/md/cookbooks_version_constraints_operators.md" >}}
+
+### Examples
+
+The following example will set `package_name` to `httpd` for the Red Hat platform and to `apache2` for the Debian platform:
+
+```ruby
+package_name = value_for_platform(
+ ['centos', 'redhat', 'suse', 'fedora' ] => {
+ 'default' => 'httpd'
+ },
+ ['ubuntu', 'debian'] => {
+ 'default' => 'apache2'
+ }
+)
+```
+
+The following example will set `package` to `apache-couchdb` for OpenBSD platforms, `dev-db/couchdb` for Gentoo platforms, and `couchdb` for all other platforms:
+
+```ruby
+package = value_for_platform(
+ 'openbsd' => { 'default' => 'apache-couchdb' },
+ 'gentoo' => { 'default' => 'dev-db/couchdb' },
+ 'default' => 'couchdb'
+)
+```
+
+The following example shows using version constraints to specify a value based on the version:
+
+```ruby
+value_for_platform(
+ 'os1' => { '< 1.0' => 'less than 1.0',
+ '~> 2.0' => 'version 2.x',
+ '>= 3.0' => 'greater than or equal to version 3.0',
+ '3.0.1' => '3.0.1 will always use this value' }
+)
+```
+
+## value_for_platform_family
+
+Use the `value_for_platform_family` method in a recipe to select a value based on the `node['platform_family']` attribute. This value is detected by Ohai during every Chef Infra Client run.
+
+The syntax for the `value_for_platform_family` method is as follows:
+
+```ruby
+value_for_platform_family( 'platform_family' => 'value', ... )
+```
+
+where:
+
+- `'platform_family' => 'value', ...` is a comma-separated list of platforms, such as Fedora, openSUSE, or Red Hat Enterprise Linux
+- `value` specifies the value that will be used if the node's platform family matches the `value_for_platform_family` method
+
+When each value only has a single platform, use the following syntax:
+
+```ruby
+value_for_platform_family(
+ 'platform_family' => 'value',
+ 'platform_family' => 'value',
+ 'platform_family' => 'value'
+)
+```
+
+When each value has more than one platform, the syntax changes to:
+
+```ruby
+value_for_platform_family(
+ ['platform_family', 'platform_family', 'platform_family', 'platform_family' ] => 'value',
+ ['platform_family', 'platform_family'] => 'value',
+ 'default' => 'value'
+)
+```
+
+The following example will set `package` to `httpd-devel` for the Red Hat Enterprise Linux, Fedora, and openSUSE platforms and to `apache2-dev` for the Debian platform:
+
+```ruby
+package = value_for_platform_family(
+ ['rhel', 'fedora', 'suse'] => 'httpd-devel',
+ 'debian' => 'apache2-dev'
+)
+```
diff --git a/content/infra_language/cookbook_execution.md b/content/infra_language/cookbook_execution.md
new file mode 100644
index 0000000..73d6bd6
--- /dev/null
+++ b/content/infra_language/cookbook_execution.md
@@ -0,0 +1,160 @@
++++
+title = "Chef Infra Language: Cookbook Execution"
+draft = false
+
+[menu]
+ [menu.infra_language]
+ title = "Cookbook Execution"
+ identifier = "infra_language/cookbook_execution.md Cookbook Execution"
+ parent = "infra_language"
++++
+
+The Chef Infra Language includes helper methods for gathering information on the execution of the Chef Infra Client recipe and resource code. This information can be used in recipes and resources to take specific actions.
+
+## Chef Infra Client State
+
+These helpers allow you to understand the state of the node that Chef Infra Client is executing on.
+
+### node
+
+Use the `node` method, often referred to as the node object, to access data collected on the system through [Ohai](/features/ohai) as well as node attributes set in cookbooks or Policyfiles.
+
+The syntax for the `node` method is as follows:
+
+```ruby
+node['specific_attribute']
+```
+
+### cookbook_name
+
+Use the `cookbook_name` method to return the name of a cookbook.
+
+The syntax for the `cookbook_name` method is as follows:
+
+```ruby
+cookbook_name
+```
+
+This method is often used as part of a log entry. For example:
+
+```ruby
+Chef::Log.info("I am a message from the #{recipe_name} recipe in the #{cookbook_name} cookbook.")
+```
+
+### recipe_name
+
+Use the `recipe_name` method to return the name of a recipe.
+
+The syntax for the `recipe_name` method is as follows:
+
+```ruby
+recipe_name
+```
+
+This method is often used as part of a log entry. For example:
+
+```ruby
+Chef::Log.info("I am a message from the #{recipe_name} recipe in the #{cookbook_name} cookbook.")
+```
+
+### resources
+
+Use the `resources` method to look up a resource in the resource collection. The `resources` method returns the value for the resource that it finds in the resource collection. The preferred syntax for the `resources` method is as follows:
+
+```ruby
+resources('resource_type[resource_name]')
+```
+
+but the following syntax can also be used:
+
+```ruby
+resources(resource_type: 'resource_name')
+```
+
+where in either approach `resource_type` is the name of a resource and `resource_name` is the name of a resource that can be configured by Chef Infra Client.
+
+The `resources` method can be used to modify a resource later on in a recipe. For example:
+
+```ruby
+file '/etc/hosts' do
+ content '127.0.0.1 localhost.localdomain localhost'
+end
+```
+
+and then later in the same recipe, or elsewhere:
+
+```ruby
+f = resources('file[/etc/hosts]')
+f.mode '0644'
+```
+
+where `file` is the type of resource, `/etc/hosts` is the name, and `f.mode` is used to set the `mode` property on the **file** resource.
+
+### attribute?
+
+Use the `attribute?` method to ensure that certain actions only execute in the presence of a particular node attribute. The `attribute?` method will return true if one of the listed node attributes matches a node attribute that's detected by Ohai during every Chef Infra Client run.
+
+The syntax for the `attribute?` method is as follows:
+
+```ruby
+attribute?('name_of_attribute')
+```
+
+For example:
+
+```ruby
+if node.attribute?('ipaddress')
+ # the node has an IP address
+end
+```
+
+### reboot_pending?
+
+Use the `reboot_pending?` method to test if a node needs a reboot, or is expected to reboot. `reboot_pending?` returns `true` when the node needs a reboot.
+
+The syntax for the `reboot_pending?` method is as follows:
+
+```ruby
+reboot_pending?
+```
+
+## Executing Code
+
+These helpers allow you to include recipes and impact how resources run on the system.
+
+### include_recipe
+
+{{< readfile file="content/reusable/md/cookbooks_recipe_include_in_recipe.md" >}}
+
+### with_run_context
+
+Use the `with_run_context` method to define a block that has a pointer to a location in the `run_context` hierarchy. Resources in recipes always run at the root of the `run_context` hierarchy, whereas custom resources and notification blocks always build a child `run_context` which contains their sub-resources.
+
+The syntax for the `with_run_context` method is as follows:
+
+```ruby
+with_run_context :type do
+ # some arbitrary pure Ruby stuff goes here
+end
+```
+
+where `:type` may be one of the following:
+
+- `:root` runs the block as part of the root `run_context` hierarchy
+- `:parent` runs the block as part of the parent process in the `run_context` hierarchy
+
+For example:
+
+```ruby
+action :run do
+ with_run_context :root do
+ edit_resource(:my_thing, "accumulated state") do
+ action :nothing
+ my_array_property << accumulate_some_stuff
+ end
+ end
+ log "kick it off" do
+ notifies :run, "my_thing[accumulated state]", :delayed
+ end
+end
+```
diff --git a/content/infra_language/editing_resources.md b/content/infra_language/editing_resources.md
new file mode 100644
index 0000000..5092c4e
--- /dev/null
+++ b/content/infra_language/editing_resources.md
@@ -0,0 +1,207 @@
++++
+title = "Chef Infra Language: Editing Resources"
+draft = false
+
+[menu]
+ [menu.infra_language]
+ title = "Editing Resources"
+ identifier = "infra_language/editing_resources.md Editing Resources"
+ parent = "infra_language"
++++
+
+## declare_resource
+
+Use the `declare_resource` method to instantiate a resource and then add it to the resource collection.
+
+The syntax for the `declare_resource` method is as follows:
+
+```ruby
+declare_resource(:resource_type, 'resource_name', resource_attrs_block)
+```
+
+where:
+
+- `:resource_type` is the resource type, such as `:file` (for the **file** resource) or `:template` (for the **template** resource). Any resource available to Chef may be declared.
+- `resource_name` the property that's the default name of the resource, typically the string that appears in the `resource 'name' do` block of a resource (but not always); see the Syntax section for the resource to be declared to verify the default name property.
+- `resource_attrs_block` is a block in which properties of the instantiated resource are declared.
+
+For example:
+
+```ruby
+declare_resource(:file, '/x/y.txy', caller[0]) do
+ action :delete
+end
+```
+
+is equivalent to:
+
+```ruby
+file '/x/y.txt' do
+ action :delete
+end
+```
+
+## delete_resource
+
+Use the `delete_resource` method to find a resource in the resource collection, and then delete it.
+
+The syntax for the `delete_resource` method is as follows:
+
+```ruby
+delete_resource(:resource_type, 'resource_name')
+```
+
+where:
+
+- `:resource_type` is the resource type, such as `:file` (for the **file** resource) or `:template` (for the **template** resource). Any resource available to Chef may be declared.
+- `resource_name` the property that's the default name of the resource, typically the string that appears in the `resource 'name' do` block of a resource (but not always); see the Syntax section for the resource to be declared to verify the default name property.
+
+For example:
+
+```ruby
+delete_resource(:template, '/x/y.erb')
+```
+
+## delete_resource!
+
+Use the `delete_resource!` method to find a resource in the resource
+collection, and then delete it. If the resource isn't found, an
+exception is returned.
+
+The syntax for the `delete_resource!` method is as follows:
+
+```ruby
+delete_resource!(:resource_type, 'resource_name')
+```
+
+where:
+
+- `:resource_type` is the resource type, such as `:file` (for the **file** resource) or `:template` (for the **template** resource). Any resource available to Chef Infra may be declared.
+- `resource_name` the property that's the default name of the resource, typically the string that appears in the `resource 'name' do` block of a resource (but not always); see the Syntax section for the resource to be declared to verify the default name property.
+
+For example:
+
+```ruby
+delete_resource!(:file, '/x/file.txt')
+```
+
+## edit_resource
+
+Use the `edit_resource` method to:
+
+- Find a resource in the resource collection, and then edit it.
+- Define a resource block. If a resource block with the same name exists in the resource collection, it will be updated with the contents of the resource block defined by the `edit_resource` method. If a resource block doesn't exist in the resource collection, it will be created.
+
+The syntax for the `edit_resource` method is as follows:
+
+```ruby
+edit_resource(:resource_type, 'resource_name', resource_attrs_block)
+```
+
+where:
+
+- `:resource_type` is the resource type, such as `:file` (for the **file** resource) or `:template` (for the **template** resource). Any resource available to Chef may be declared.
+- `resource_name` the property that's the default name of the resource, typically the string that appears in the `resource 'name' do` block of a resource (but not always); see the Syntax section for the resource to be declared to verify the default name property.
+- `resource_attrs_block` is a block in which properties of the instantiated resource are declared.
+
+For example:
+
+```ruby
+edit_resource(:template, '/x/y.txy') do
+ cookbook 'cookbook_name'
+end
+```
+
+and a resource block:
+
+```ruby
+edit_resource(:template, '/etc/aliases') do
+ source 'aliases.erb'
+ cookbook 'aliases'
+ variables({:aliases => {} })
+ notifies :run, 'execute[newaliases]'
+end
+```
+
+## edit_resource!
+
+Use the `edit_resource!` method to:
+
+- Find a resource in the resource collection, and then edit it.
+- Define a resource block. If a resource with the same name exists in the resource collection, its properties will be updated with the contents of the resource block defined by the `edit_resource` method.
+
+In both cases, if the resource isn't found, an exception is returned.
+
+The syntax for the `edit_resource!` method is as follows:
+
+```ruby
+edit_resource!(:resource_type, 'resource_name')
+```
+
+where:
+
+- `:resource_type` is the resource type, such as `:file` (for the **file** resource) or `:template` (for the **template** resource). Any resource available to Chef may be declared.
+- `resource_name` the property that's the default name of the resource, typically the string that appears in the `resource 'name' do` block of a resource (but not always); see the Syntax section for the resource to be declared to verify the default name property.
+- `resource_attrs_block` is a block in which properties of the instantiated resource are declared.
+
+For example:
+
+```ruby
+edit_resource!(:file, '/x/y.rst')
+```
+
+## find_resource
+
+Use the `find_resource` method to:
+
+- Find a resource in the resource collection.
+- Define a resource block. If a resource block with the same name exists in the resource collection, it will be returned. If a resource block doesn't exist in the resource collection, it will be created.
+
+The syntax for the `find_resource` method is as follows:
+
+```ruby
+find_resource(:resource_type, 'resource_name')
+```
+
+where:
+
+- `:resource_type` is the resource type, such as `:file` (for the **file** resource) or `:template` (for the **template** resource). Any resource available to Chef may be declared.
+- `resource_name` the property that's the default name of the resource, typically the string that appears in the `resource 'name' do` block of a resource (but not always); see the Syntax section for the resource to be declared to verify the default name property.
+
+For example:
+
+```ruby
+find_resource(:template, '/x/y.txy')
+```
+
+and a resource block:
+
+```ruby
+find_resource(:template, '/etc/seapower') do
+ source 'seapower.erb'
+ cookbook 'seapower'
+ variables({:seapower => {} })
+ notifies :run, 'execute[newseapower]'
+end
+```
+
+## find_resource!
+
+Use the `find_resource!` method to find a resource in the resource collection. If the resource isn't found, an exception is returned.
+
+The syntax for the `find_resource!` method is as follows:
+
+```ruby
+find_resource!(:resource_type, 'resource_name')
+```
+
+where:
+
+- `:resource_type` is the resource type, such as `:file` (for the **file** resource) or `:template` (for the **template** resource). Any resource available to Chef may be declared.
+- `resource_name` the property that's the default name of the resource, typically the string that appears in the `resource 'name' do` block of a resource (but not always); see the Syntax section for the resource to be declared to verify the default name property.
+
+For example:
+
+```ruby
+find_resource!(:template, '/x/y.erb')
+```
diff --git a/content/infra_language/logging.md b/content/infra_language/logging.md
new file mode 100644
index 0000000..c16f958
--- /dev/null
+++ b/content/infra_language/logging.md
@@ -0,0 +1,20 @@
++++
+title = "Chef Infra Language: Logging"
+draft = false
+
+[menu]
+ [menu.infra_language]
+ title = "Logging"
+ identifier = "infra_language/logging.md Logging"
+ parent = "infra_language"
++++
+
+## Log Entries
+
+{{< readfile file="content/reusable/md/ruby_style_basics_chef_log.md" >}}
+
+### Examples
+
+{{< readfile file="content/reusable/md/ruby_class_chef_log_fatal.md" >}}
+
+{{< readfile file="content/reusable/md/ruby_class_chef_log_multiple.md" >}}
diff --git a/content/infra_language/node_tags.md b/content/infra_language/node_tags.md
new file mode 100644
index 0000000..a88ff65
--- /dev/null
+++ b/content/infra_language/node_tags.md
@@ -0,0 +1,14 @@
++++
+title = "Chef Infra Language: Node Tags"
+draft = false
+
+[menu]
+ [menu.infra_language]
+ title = "Node Tags"
+ identifier = "infra_language/node_tags.md Node Tags"
+ parent = "infra_language"
++++
+
+{{< readfile file="content/reusable/md/chef_tags.md" >}}
+
+{{< readfile file="content/reusable/md/cookbooks_recipe_tags.md" >}}
diff --git a/content/infra_language/reading_data_bags.md b/content/infra_language/reading_data_bags.md
new file mode 100644
index 0000000..4655008
--- /dev/null
+++ b/content/infra_language/reading_data_bags.md
@@ -0,0 +1,80 @@
++++
+title = "Chef Infra Language: Reading Data Bags"
+draft = false
+
+[menu]
+ [menu.infra_language]
+ title = "Reading Data Bags"
+ identifier = "infra_language/reading_data_bags.md Reading Data Bags"
+ parent = "infra_language"
++++
+
+## data_bag
+
+{{< readfile file="content/reusable/md/data_bag.md" >}}
+
+Use the `data_bag` method to get a list of the contents of a data bag.
+
+The syntax for the `data_bag` method is as follows:
+
+```ruby
+data_bag(bag_name)
+```
+
+### Examples
+
+The following example shows how the `data_bag` method can be used in a recipe.
+
+#### Get a data bag, and then iterate through each data bag item
+
+{{< readfile file="content/reusable/md/infra_lang_data_bag.md" >}}
+
+## data_bag_item
+
+{{< readfile file="content/reusable/md/data_bag.md" >}}
+
+The `data_bag_item` method can be used in a recipe to get the contents of a data bag item.
+
+The syntax for the `data_bag_item` method is as follows:
+
+```ruby
+data_bag_item(bag_name, item, secret)
+```
+
+where `secret` is the secret used to load an encrypted data bag. If `secret` isn't specified, Chef Infra Client looks for a secret at the path specified by the `encrypted_data_bag_secret` setting in the `client.rb` file.
+
+### Examples
+
+The following examples show how the `data_bag_item` method can be used in a recipe.
+
+#### Get a data bag, and then iterate through each data bag item
+
+{{< readfile file="content/reusable/md/infra_lang_data_bag.md" >}}
+
+#### Use the contents of a data bag in a recipe
+
+The following example shows how to use the `data_bag` and `data_bag_item` methods in a recipe, also using a data bag named `sea-power`):
+
+```ruby
+package 'sea-power' do
+ action :install
+end
+
+directory node['sea-power']['base_path'] do
+ # attributes for owner, group, mode
+end
+
+gale_warnings = data_bag('sea-power').map do |viking_north|
+ data_bag_item('sea-power', viking_north)['source']
+end
+
+template '/etc/seattle/power.list' do
+ source 'seattle-power.erb'
+ # attributes for owner, group, mode
+ variables(
+ :base_path => node['sea-power']['base_path'],
+ # more variables
+ :repo_location => gale_warnings
+ )
+end
+```
diff --git a/content/infra_language/registry_keys.md b/content/infra_language/registry_keys.md
new file mode 100644
index 0000000..a75b62e
--- /dev/null
+++ b/content/infra_language/registry_keys.md
@@ -0,0 +1,92 @@
++++
+title = "Chef Infra Language: Reading Registry Keys"
+draft = false
+
+[menu]
+ [menu.infra_language]
+ title = "Reading Registry Keys"
+ identifier = "infra_language/registry_key.md Reading Registry Keys"
+ parent = "infra_language"
++++
+
+{{< readfile file="content/reusable/md/infra_lang_method_windows_methods.md" >}}
+
+{{< note >}}
+
+The recommended order in which registry key-specific methods should be
+used within a recipe is: `key_exists?`, `value_exists?`, `data_exists?`,
+`get_values`, `has_subkeys?`, and then `get_subkeys`.
+
+{{< /note >}}
+
+## registry_data_exists?
+
+{{< readfile file="content/reusable/md/infra_lang_method_registry_data_exists.md" >}}
+
+{{< note >}}
+
+{{< readfile file="content/reusable/md/notes_registry_key_not_if_only_if.md" >}}
+
+{{< /note >}}
+
+{{< readfile file="content/reusable/md/infra_lang_method_registry_data_exists_syntax.md" >}}
+
+## registry_get_subkeys
+
+{{< readfile file="content/reusable/md/infra_lang_method_registry_get_subkeys.md" >}}
+
+{{< note >}}
+
+{{< readfile file="content/reusable/md/notes_registry_key_not_if_only_if.md" >}}
+
+{{< /note >}}
+
+{{< readfile file="content/reusable/md/infra_lang_method_registry_get_subkeys_syntax.md" >}}
+
+## registry_get_values
+
+{{< readfile file="content/reusable/md/infra_lang_method_registry_get_values.md" >}}
+
+{{< note >}}
+
+{{< readfile file="content/reusable/md/notes_registry_key_not_if_only_if.md" >}}
+
+{{< /note >}}
+
+{{< readfile file="content/reusable/md/infra_lang_method_registry_get_values_syntax.md" >}}
+
+## registry_has_subkeys?
+
+{{< readfile file="content/reusable/md/infra_lang_method_registry_has_subkeys.md" >}}
+
+{{< note >}}
+
+{{< readfile file="content/reusable/md/notes_registry_key_not_if_only_if.md" >}}
+
+{{< /note >}}
+
+{{< readfile file="content/reusable/md/infra_lang_method_registry_has_subkeys_syntax.md" >}}
+
+## registry_key_exists?
+
+{{< readfile file="content/reusable/md/infra_lang_method_registry_key_exists.md" >}}
+
+{{< note >}}
+
+{{< readfile file="content/reusable/md/notes_registry_key_not_if_only_if.md" >}}
+
+{{< /note >}}
+
+{{< readfile file="content/reusable/md/infra_lang_method_registry_key_exists_syntax.md" >}}
+
+## registry_value_exists?
+
+{{< readfile file="content/reusable/md/infra_lang_method_registry_value_exists.md" >}}
+
+{{< note >}}
+
+{{< readfile file="content/reusable/md/notes_registry_key_not_if_only_if.md" >}}
+
+{{< /note >}}
+
+{{< readfile file="content/reusable/md/infra_lang_method_registry_value_exists_syntax.md" >}}
diff --git a/content/infra_language/ruby.md b/content/infra_language/ruby.md
new file mode 100644
index 0000000..e6a25e0
--- /dev/null
+++ b/content/infra_language/ruby.md
@@ -0,0 +1,689 @@
++++
+title = "Ruby Guide"
+draft = false
+
+[menu]
+ [menu.infra_language]
+ title = "Ruby Guide"
+ identifier = "infra_language/ruby.md Ruby Guide"
+ parent = "infra_language"
++++
+
+{{< readfile file="content/reusable/md/ruby_summary.md" >}}
+
+## Ruby basics
+
+This section covers the basics of Ruby.
+
+### Verify syntax
+
+Many people who are new to Ruby often find that it doesn't take
+long to get up to speed with the basics. For example, it's useful to
+know how to check the syntax of a Ruby file, such as the contents of a
+cookbook named `my_cookbook.rb`:
+
+```bash
+ruby -c my_cookbook_file.rb
+```
+
+to return:
+
+```bash
+Syntax OK
+```
+
+### Comments
+
+Use a comment to explain code that exists in a cookbook or recipe.
+Anything after a `#` is a comment.
+
+```ruby
+# This is a comment.
+```
+
+### Local variables
+
+Assign a local variable:
+
+```ruby
+x = 1
+```
+
+### Math
+
+Do some basic arithmetic:
+
+```ruby
+1 + 2 # => 3
+2 * 7 # => 14
+5 / 2 # => 2 (because both arguments are whole numbers)
+5 / 2.0 # => 2.5 (because one of the numbers had a decimal place)
+1 + (2 * 3) # => 7 (you can use parentheses to group expressions)
+```
+
+### Strings
+
+Work with strings:
+
+```ruby
+'single quoted' # => "single quoted"
+"double quoted" # => "double quoted"
+'It\'s alive!' # => "It's alive!" (the \ is an escape character)
+'1 + 2 = 5' # => "1 + 2 = 5" (numbers surrounded by quotes behave like strings)
+```
+
+Convert a string to uppercase or lowercase. For example, a hostname
+named "Foo":
+
+```ruby
+node['hostname'].downcase # => "foo"
+node['hostname'].upcase # => "FOO"
+```
+
+#### Ruby in strings
+
+Embed Ruby in a string:
+
+```ruby
+x = 'Bob'
+"Hi, #{x}" # => "Hi, Bob"
+'Hello, #{x}' # => "Hello, \#{x}" Notice that single quotes don't work with #{}
+```
+
+#### Escape character
+
+Use the backslash character (`\`) as an escape character when quotes
+must appear within strings. However, you don't need to escape single
+quotes inside double quotes. For example:
+
+```ruby
+'It\'s alive!' # => "It's alive!"
+"Won\'t you read Grant\'s book?" # => "won't you read Grant's book?"
+```
+
+#### Interpolation
+
+When strings have quotes within quotes, use double quotes (`" "`) on the
+outer quotes, and then single quotes (`' '`) for the inner quotes. For
+example:
+
+```ruby
+Chef::Log.info("Loaded from aws[#{aws['id']}]")
+```
+
+```ruby
+"node['mysql']['secretpath']"
+```
+
+```ruby
+"#{ENV['HOME']}/chef.txt"
+```
+
+```ruby
+antarctica_hint = hint?('antarctica')
+if antarctica_hint['snow']
+ "There are #{antarctica_hint['penguins']} penguins here."
+else
+ 'There is no snow here, and penguins like snow.'
+end
+```
+
+### Truths
+
+Work with basic truths:
+
+```ruby
+true # => true
+false # => false
+nil # => nil
+0 # => true ( the only false values in Ruby are false
+ # and nil; in other words: if it exists in Ruby,
+ # even if it exists as zero, then it's true.)
+1 == 1 # => true ( == tests for equality )
+1 == true # => false ( == tests for equality )
+```
+
+#### Untruths
+
+Work with basic untruths (`!` means not!):
+
+```ruby
+!true # => false
+!false # => true
+!nil # => true
+1 != 2 # => true (1 isn't equal to 2)
+1 != 1 # => false (1 isn't equal to itself)
+```
+
+#### Convert to boolean
+
+Convert a value to either `true` or `false` using the double negation operator (`!!`).
+The first `!` converts the value to its opposite boolean, and the second `!` converts it back, resulting in the boolean representation of the original value:
+
+```ruby
+!!true # => true
+!!false # => false
+!!nil # => false (nil evaluates to false)
+!!0 # => true (zero evaluates to true)
+```
+
+### Arrays
+
+Create lists using arrays:
+
+```ruby
+x = ['a', 'b', 'c'] # => ["a", "b", "c"]
+x[0] # => "a" (zero is the first index)
+x.first # => "a" (see?)
+x.last # => "c"
+x + ['d'] # => ["a", "b", "c", "d"]
+x # => ["a", "b", "c"] ( x is unchanged)
+x = x + ['d'] # => ["a", "b", "c", "d"]
+x # => ["a", "b", "c", "d"]
+```
+
+#### Whitespace Arrays
+
+The `%w` syntax is a Ruby shortcut for creating an array without
+requiring quotes and commas around the elements.
+
+For example:
+
+```ruby
+if %w(debian ubuntu).include?(node['platform'])
+ # do debian/ubuntu things with the Ruby array %w() shortcut
+end
+```
+
+{{< readfile file="content/reusable/md/ruby_style_patterns_string_quoting_vs_whitespace_array.md" >}}
+
+##### Example
+
+WiX includes several tools -- such as `candle` (preprocesses and
+compiles source files into object files), `light` (links and binds
+object files to an installer database), and `heat` (harvests files from
+various input formats). The following example uses a whitespace array
+and the Chef InSpec `file` audit resource to verify if these three tools
+are present:
+
+```ruby
+%w(
+ candle.exe
+ heat.exe
+ light.exe
+).each do |utility|
+ describe file("C:/wix/#{utility}") do
+ it { should be_file }
+ end
+end
+```
+
+### Hash
+
+A Hash is a list with keys and values. Sometimes hashes don't have a set
+order:
+
+```ruby
+h = {
+ 'first_name' => 'Bob',
+ 'last_name' => 'Jones',
+}
+```
+
+And sometimes they do. For example, first name then last name:
+
+```ruby
+h.keys # => ["first_name", "last_name"]
+h['first_name'] # => "Bob"
+h['last_name'] # => "Jones"
+h['age'] = 23
+h.keys # => ["first_name", "age", "last_name"]
+h.values # => ["Jones", "Bob", 23]
+```
+
+### Regular Expressions
+
+Use Perl-style regular expressions:
+
+```ruby
+'I believe' =~ /I/ # => 0 (matches at the first character)
+'I believe' =~ /lie/ # => 4 (matches at the 5th character)
+'I am human' =~ /bacon/ # => nil (no match - bacon comes from pigs)
+'I am human' !~ /bacon/ # => true (correct, no bacon here)
+/give me a ([0-9]+)/ =~ 'give me a 7' # => 0 (matched)
+```
+
+### Statements
+
+Use conditions! For example, an `if` statement
+
+```ruby
+if false
+ # this won't happen
+elsif nil
+ # this won't either
+else
+ # code here will run though
+end
+```
+
+or a `case` statement:
+
+```ruby
+x = 'dog'
+case x
+when 'fish'
+ # this won't happen
+when 'dog', 'cat', 'monkey'
+ # this will run
+else
+ # the else is an optional catch-all
+end
+```
+
+#### if
+
+An `if` statement can be used to specify part of a recipe to be used
+when certain conditions are met. `else` and `elsif` statements can be
+used to handle situations where either the initial condition isn't met
+or when there are other possible conditions that can be met. Since this
+behavior is 100% Ruby, do this in a recipe the same way here as anywhere
+else.
+
+For example, using an `if` statement with the `platform` node attribute:
+
+```ruby
+if node['platform'] == 'ubuntu'
+ # do ubuntu things
+end
+```
+
+##### if modifier
+
+`if` can be used as a modifier that executes the left side of an expression
+if the right side of the expression is true. The `if` modifier expression must
+be a single line, and `else` and `elsif` statements aren't supported.
+
+In the following example, the `do_ubuntu_thing` function will execute if the platform on a node is Ubuntu.
+
+```ruby
+do_ubuntu_thing if platform?('ubuntu')
+```
+
+#### case
+
+A `case` statement can be used to handle a situation where there are a
+lot of conditions. Use the `when` statement for each condition, as many
+as are required.
+
+For example, using a `case` statement with the `platform` node
+attribute:
+
+```ruby
+case node['platform']
+when 'debian', 'ubuntu'
+ # do debian/ubuntu things
+when 'redhat', 'centos', 'fedora'
+ # do redhat/centos/fedora things
+end
+```
+
+For example, using a `case` statement with the `platform_family` node
+attribute:
+
+```ruby
+case node['platform_family']
+when 'debian'
+ # do things on debian-ish platforms (debian, ubuntu, linuxmint)
+when 'rhel'
+ # do things on RHEL platforms (redhat, centos, scientific, etc)
+end
+```
+
+### Call a Method
+
+Call a method on something with `.method_name()`:
+
+```ruby
+x = 'My String'
+x.split(' ') # => ["My", "String"]
+x.split(' ').join(', ') # => "My, String"
+```
+
+### Define a Method
+
+Define a method (or a function, if you like):
+
+```ruby
+def do_something_useless(first_argument, second_argument)
+ puts "You gave me #{first_argument} and #{second_argument}"
+end
+
+do_something_useless('apple', 'banana')
+# => "You gave me apple and banana"
+do_something_useless 1, 2
+# => "You gave me 1 and 2"
+# see how the parentheses are optional if there's no confusion about what to do
+```
+
+### Ruby Class
+
+Use the Ruby `File` class in a recipe. Because Chef has the **file**
+resource, use `File` to use the Ruby `File` class. For example:
+
+```ruby
+execute 'apt-get-update' do
+ command 'apt-get update'
+ ignore_failure true
+ not_if { ::File.exist?('/var/lib/apt/periodic/update-success-stamp') }
+end
+```
+
+### Include a Class
+
+Use `:include` to include another Ruby class. For example:
+
+```ruby
+::Chef::DSL::Recipe.include MyCookbook::Helpers
+```
+
+In non-Chef Ruby, the syntax is `include` (without the `:` prefix), but
+without the `:` prefix Chef Infra Client will try to find a provider
+named `include`. Using the `:` prefix tells Chef Infra Client to look
+for the specified class that follows.
+
+### Include a Parameter
+
+The `include?` method can be used to ensure that a specific parameter is
+included before an action is taken. For example, using the `include?`
+method to find a specific parameter:
+
+```ruby
+if %w(debian ubuntu).include?(node['platform'])
+ # do debian/ubuntu things
+end
+```
+
+or:
+
+```ruby
+if %w(rhel).include?(node['platform_family'])
+ # do RHEL things
+end
+```
+
+## Patterns to follow
+
+This section covers best practices for cookbook and recipe authoring.
+
+### Git etiquette
+
+Although not strictly a Chef style thing, please always ensure your
+`user.name` and `user.email` are set properly in your `.gitconfig` file.
+
+- `user.name` should be your given name (for example, "Julian Dunn")
+- `user.email` should be an actual, working e-mail address
+
+This will prevent commit log entries similar to
+`"guestuser "`, which are unhelpful.
+
+### Use of hyphens
+
+{{< readfile file="content/reusable/md/ruby_style_patterns_hyphens.md" >}}
+
+### Cookbook naming
+
+Use a short organizational prefix for application cookbooks that are
+part of your organization. For example, if your organization is named
+SecondMarket, use `sm` as a prefix: `sm_postgresql` or `sm_httpd`.
+
+### Cookbook versioning
+
+- Use semantic versioning when numbering cookbooks.
+- Only upload stable cookbooks from the main or default branch.
+- Only upload unstable cookbooks from a development branch. Merge to main and bump the version when stable.
+- Always update CHANGELOG.md with any changes, with the JIRA ticket and a brief description.
+
+### Naming
+
+Name things uniformly for their system and component. For example:
+
+- attributes: `node['foo']['bar']`
+- recipe: `foo::bar`
+- role: `foo-bar`
+- directories: `foo/bar` (if specific to component), `foo` (if not).
+ For example: `/var/log/foo/bar`.
+
+Name attributes after the recipe in which they're primarily used. for example
+`node['postgresql']['server']`.
+
+### Parameter order
+
+Follow this order for information in each resource declaration:
+
+- Source
+- Cookbook
+- Resource ownership
+- Permissions
+- Notifications
+- Action
+
+For example:
+
+```ruby
+template '/tmp/foobar.txt' do
+ source 'foobar.txt.erb'
+ owner 'someuser'
+ group 'somegroup'
+ mode '0644'
+ variables(
+ foo: 'bar'
+ )
+ notifies :reload, 'service[whatever]'
+ action :create
+end
+```
+
+### File modes
+
+Always specify the file mode with a quoted 3 to 5 character string that
+defines the octal mode:
+
+```ruby
+mode '755'
+```
+
+```ruby
+mode '0755'
+```
+
+Wrong:
+
+```ruby
+mode 755
+```
+
+### Specify resource action?
+
+A resource declaration doesn't require the action to be specified
+because Chef Infra Client will apply the default action for a resource
+automatically if it's not specified within the resource block. For
+example:
+
+```ruby
+package 'monit'
+```
+
+will install the `monit` package because the `:install` action is the
+default action for the **package** resource.
+
+However, if readability of code is desired, such as ensuring that a
+reader understands what the default action is for a custom resource or
+stating the action for a resource whose default may not be immediately
+obvious to the reader, specifying the default action is recommended:
+
+```ruby
+ohai 'apache_modules' do
+ action :reload
+end
+```
+
+### String quoting
+
+Use single-quoted strings in all situations where the string doesn't
+need interpolation.
+
+#### Whitespace arrays
+
+{{< readfile file="content/reusable/md/ruby_style_patterns_string_quoting_vs_whitespace_array.md" >}}
+
+### Recipes
+
+A recipe should be clean and well-commented. For example:
+
+```ruby
+###########
+# variables
+###########
+
+connection_info = {
+ host: '127.0.0.1',
+ port: '3306',
+ username: 'root',
+ password: 'm3y3sqlr00t',
+}
+
+#################
+# Mysql resources
+#################
+
+mysql_service 'default' do
+ port '3306'
+ initial_root_password 'm3y3sqlr00t'
+ action [:create, :start]
+end
+
+mysql_database 'wordpress_demo' do
+ connection connection_info
+ action :create
+end
+
+mysql_database_user 'wordpress_user' do
+ connection connection_info
+ database_name 'wordpress_demo'
+ password 'w0rdpr3ssdem0'
+ privileges [:create, :delete, :select, :update, :insert]
+ action :grant
+end
+
+##################
+# Apache resources
+##################
+
+httpd_service 'default' do
+ listen_ports %w(80)
+ mpm 'prefork'
+ action [:create, :start]
+end
+
+httpd_module 'php' do
+ notifies :restart, 'httpd_service[default]'
+ action :create
+end
+
+###############
+# Php resources
+###############
+
+package 'php-gd' do
+ action :install
+end
+
+package 'php-mysql' do
+ action :install
+end
+
+directory '/etc/php.d' do
+ action :create
+end
+
+template '/etc/php.d/mysql.ini' do
+ source 'mysql.ini.erb'
+ action :create
+end
+
+httpd_config 'php' do
+ source 'php.conf.erb'
+ notifies :restart, 'httpd_service[default]'
+ action :create
+end
+
+#####################
+# wordpress resources
+#####################
+
+directory '/srv/wordpress_demo' do
+ user 'apache'
+ recursive true
+ action :create
+end
+
+tar_extract 'https://wordpress.org/wordpress-4.1.tar.gz' do
+ target_dir '/srv/wordpress_demo'
+ tar_flags ['--strip-components 1']
+ user 'apache'
+ creates '/srv/wordpress_demo/index.php'
+ action :extract
+end
+
+directory '/srv/wordpress_demo/wp-content' do
+ user 'apache'
+ action :create
+end
+
+httpd_config 'wordpress' do
+ source 'wordpress.conf.erb'
+ variables(
+ servername: 'wordpress',
+ server_aliases: %w(computers.biz www.computers.biz),
+ document_root: '/srv/wordpress_demo'
+ )
+ notifies :restart, 'httpd_service[default]'
+ action :create
+end
+
+template '/srv/wordpress_demo/wp-config.php' do
+ source 'wp-config.php.erb'
+ owner 'apache'
+ variables(
+ db_name: 'wordpress_demo',
+ db_user: 'wordpress_user',
+ db_password: 'w0rdpr3ssdem0',
+ db_host: '127.0.0.1',
+ db_prefix: 'wp_',
+ db_charset: 'utf8',
+ auth_key: 'You should probably use randomly',
+ secure_auth_key: 'generated strings. These can be hard',
+ logged_in_key: 'coded, pulled from encrypted databags,',
+ nonce_key: 'or a ruby function that accessed an',
+ auth_salt: 'arbitrary data source, such as a password',
+ secure_auth_salt: 'vault. Node attributes could work',
+ logged_in_salt: 'as well, but you take special care',
+ nonce_salt: 'so they're not saved to your chef-server.',
+ allow_multisite: 'false'
+ )
+ action :create
+end
+```
+
+## Cookstyle linting
+
+Chef Workstation includes Cookstyle for linting the Ruby-specific and
+Chef-specific portions of your cookbook code. All cookbooks should pass
+Cookstyle rules before being uploaded.
+
+```bash
+cookstyle cookbook-name
+```
+
+This command should return `no offenses detected`.
diff --git a/content/infra_language/search.md b/content/infra_language/search.md
new file mode 100644
index 0000000..c36a319
--- /dev/null
+++ b/content/infra_language/search.md
@@ -0,0 +1,147 @@
++++
+title = "Chef Infra Language: Search"
+draft = false
+
+[menu]
+ [menu.infra_language]
+ title = "Search"
+ identifier = "infra_language/search.md Search"
+ parent = "infra_language"
++++
+
+## search
+
+{{< readfile file="content/reusable/md/search.md" >}}
+
+Use the `search` method to perform a search query against Chef Infra Server from within a recipe.
+
+The syntax for the `search` method is as follows:
+
+```ruby
+search(:index, 'query')
+```
+
+where:
+
+- `:index` is of name of the index on Chef Infra Server against which the search query will run: `:client`, `:data_bag_name`, `:environment`, `:node`, and `:role`
+- `'query'` is a valid search query against an object on Chef Infra Server (see below for more information about how to build the query)
+
+For example, using the results of a search query within a variable:
+
+```ruby
+webservers = search(:node, 'role:webserver')
+```
+
+and then using the results of that query to populate a template:
+
+```ruby
+template '/tmp/list_of_webservers' do
+ source 'list_of_webservers.erb'
+ variables(:webservers => webservers)
+end
+```
+
+### :filter_result
+
+{{< readfile file="content/reusable/md/infra_lang_method_search_filter_result.md" >}}
+
+### Query Syntax
+
+{{< readfile file="content/reusable/md/search_query_syntax.md" >}}
+
+#### Keys
+
+{{< readfile file="content/reusable/md/search_key.md" >}}
+
+#### Nested Fields
+
+{{< readfile file="content/reusable/md/search_key_nested.md" >}}
+
+#### Patterns
+
+{{< readfile file="content/reusable/md/search_pattern.md" >}}
+
+#### Exact Match
+
+{{< readfile file="content/reusable/md/search_pattern_exact.md" >}}
+
+#### Wildcard Match
+
+{{< readfile file="content/reusable/md/search_pattern_wildcard.md" >}}
+
+#### Range Match
+
+{{< readfile file="content/reusable/md/search_pattern_range.md" >}}
+
+#### Fuzzy Match
+
+{{< readfile file="content/reusable/md/search_pattern_fuzzy.md" >}}
+
+#### Operators
+
+{{< readfile file="content/reusable/md/search_boolean_operators.md" >}}
+
+#### Special Characters
+
+{{< readfile file="content/reusable/md/search_special_characters.md" >}}
+
+### Examples
+
+The following examples show how the `search` method can be used in a recipe.
+
+#### Use the search helper to find users
+
+The following example shows how to use the `search` method in the Recipe
+DSL to search for users:
+
+```ruby
+# the following code sample comes from the openvpn cookbook: https://github.com/chef-cookbooks/openvpn
+
+search("users", "*:*") do |u|
+ execute "generate-openvpn-#{u['id']}" do
+ command "./pkitool #{u['id']}"
+ cwd '/etc/openvpn/easy-rsa'
+ environment(
+ 'EASY_RSA' => '/etc/openvpn/easy-rsa',
+ 'KEY_CONFIG' => '/etc/openvpn/easy-rsa/openssl.cnf',
+ 'KEY_DIR' => node['openvpn']['key_dir'],
+ 'CA_EXPIRE' => node['openvpn']['key']['ca_expire'].to_s,
+ 'KEY_EXPIRE' => node['openvpn']['key']['expire'].to_s,
+ 'KEY_SIZE' => node['openvpn']['key']['size'].to_s,
+ 'KEY_COUNTRY' => node['openvpn']['key']['country'],
+ 'KEY_PROVINCE' => node['openvpn']['key']['province'],
+ 'KEY_CITY' => node['openvpn']['key']['city'],
+ 'KEY_ORG' => node['openvpn']['key']['org'],
+ 'KEY_EMAIL' => node['openvpn']['key']['email']
+ )
+ not_if { File.exist?("#{node['openvpn']['key_dir']}/#{u['id']}.crt") }
+ end
+
+ %w{ conf ovpn }.each do |ext|
+ template "#{node['openvpn']['key_dir']}/#{u['id']}.#{ext}" do
+ source 'client.conf.erb'
+ variables :username => u['id']
+ end
+ end
+
+ execute "create-openvpn-tar-#{u['id']}" do
+ cwd node['openvpn']['key_dir']
+ command <<-EOH
+ tar zcf #{u['id']}.tar.gz \
+ ca.crt #{u['id']}.crt #{u['id']}.key \
+ #{u['id']}.conf #{u['id']}.ovpn \
+ EOH
+ not_if { File.exist?("#{node['openvpn']['key_dir']}/#{u['id']}.tar.gz") }
+ end
+end
+```
+
+where
+
+- the search will use both of the **execute** resources, unless the
+ condition specified by the `not_if` commands are met
+- the `environments` property in the first **execute** resource is
+ being used to define values that appear as variables in the OpenVPN
+ configuration
+- the **template** resource tells Chef Infra Client which template to
+ use
diff --git a/content/infra_language/secrets.md b/content/infra_language/secrets.md
new file mode 100644
index 0000000..f26588f
--- /dev/null
+++ b/content/infra_language/secrets.md
@@ -0,0 +1,223 @@
++++
+title = "Chef Infra Language: Secrets"
+draft = false
+
+[menu]
+ [menu.infra_language]
+ title = "Secrets Management Integrations"
+ identifier = "infra_language/secrets.md Secrets Management Integrations"
+ parent = "infra_language"
++++
+
+The Secrets Management Integration helper is a beta feature starting in Chef Infra Client 17.5 and became a fully supported feature in Chef Infra Client 18.
+This helper allows you to access secrets from the following secrets management systems within your Infra recipes or resources:
+
+- AWS Secrets Manager
+- Akeyless Vault
+- Azure Key Vault
+- HashiCorp Vault
+
+## Syntax
+
+Use the following syntax to fetch secrets:
+
+```ruby
+secret(name: '', version: '', service: , config: {key: value})
+```
+
+
+
+Replace the following:
+
+``
+: The identifier or name for this secret.
+
+``
+: The secret version. If a service supports versions and you don't provide a version, the Secrets Management Integration helper fetches the latest version.
+
+ Secret versions supported with:
+
+ - AWS Secrets Manager
+ - Azure Key Vault
+
+``
+: The secret manager.
+
+ Allowed values:
+
+ - `:akeyless_vault`
+ - `:aws_secrets_manager`
+ - `:azure_key_vault`
+ - `:hashi_vault`
+
+`config`
+: Use `config` to set key/value settings passed to a secrets manager. For example, to set the AWS region that a secret is stored in with AWS Secrets Manager, add `config: {region: 'us-west-2'}`.
+
+
+
+### Set defaults
+
+You can set a default service and service configuration and then the Secrets Management Integration helper will use those settings every time you request a secret.
+This is useful if you want to request more than one secret from the same service.
+
+Use the `default_secret_service` and `default_secret_config` to define a default service and service configuration:
+
+```ruby
+default_secret_service()
+default_secret_config(key: "value")
+
+value1 = secret(name: "")
+value2 = secret(name: "")
+value3 = secret(name: "")
+```
+
+Or wrap your secret definitions using `with_secret_service` and `with_secret_config`:
+
+```ruby
+with_secret_service() do
+ with_secret_config(key: "value") do
+ value1 = secret(name: "")
+ value2 = secret(name: "")
+ value3 = secret(name: "")
+ end
+end
+```
+
+Define a default secret service and then fetch secrets with different configs:
+
+```ruby
+default_secret_service()
+
+with_secret_config(key: "") do
+ secret_1 = secret(name: "")
+ secret_2 = secret(name: "")
+end
+
+with_secret_config(key: "") do
+ secret_3 = secret(name: "")
+ secret_4 = secret(name: "")
+end
+```
+
+## Examples
+
+### Akeyless Vault
+
+Fetch secrets from Akeyless Vault using the access key and access ID:
+
+```ruby
+secret(name: '',
+ service: :akeyless_vault,
+ config: {
+ access_key: '',
+ access_id: ''
+ })
+```
+
+### AWS Secrets Manager
+
+Fetch a secret from AWS Secrets Manager:
+
+```ruby
+secret(name: '', service: :aws_secrets_manager)
+```
+
+Specify an AWS region:
+
+```ruby
+secret(name: '', service: :aws_secrets_manager, config: { region: '' })
+```
+
+### Azure Key Vault
+
+Fetch secrets from Azure Key Vault:
+
+```ruby
+secret(name: '', service: :azure_key_vault)
+```
+
+Specify the vault name in the config:
+
+```ruby
+secret(name: '', service: :azure_key_vault, config: { vault: '' })
+```
+
+Fetch a specific version of an Azure Key Vault secret:
+
+```ruby
+secret(name: '', version: 'v1', service: :azure_key_vault)
+```
+
+### HashiCorp Vault
+
+Fetch secrets from HashiCorp Vault using AWS IAM:
+
+```ruby
+secret(name: '',
+ service: :hashi_vault,
+ config: {
+ vault_addr: 'vault.example.com',
+ role_name: ''
+ })
+```
+
+Fetch secrets from HashiCorp Vault using tokens:
+
+```ruby
+secret(name: '',
+ service: :hashi_vault,
+ config: {
+ vault_addr: 'vault.example.com',
+ auth_method: :token,
+ token: ''
+ })
+```
+
+Fetch secrets from HashiCorp Vault using AppRole ID and an associated AppRole Secret ID:
+
+```ruby
+secret(name: '',
+ service: :hashi_vault,
+ config: {
+ vault_addr: 'vault.example.com',
+ auth_method: :approle,
+ approle_id: "",
+ approle_secret_id: ""
+ })
+```
+
+Fetch secrets using a token and an AppRole name creates a Secret ID associated with that AppRole:
+
+```ruby
+secret(name: '',
+ service: :hashi_vault,
+ config: {
+ vault_addr: 'vault.example.com',
+ auth_method: :approle,
+ approle_name: "",
+ token: ''
+ })
+```
+
+### Fetch secrets in cookbooks
+
+The secrets helper returns a text string, so you can use it anywhere in Chef Infra where you might hard code a value or access a value from a data bag.
+
+Write a secret to a file:
+
+```ruby
+file '/home/ubuntu/aws-secret' do
+ content secret(name: '', service: :aws_secrets_manager)
+end
+```
+
+Pass a secret to a template:
+
+```ruby
+template '/etc/my_fancy_service/my_fancy_service.conf' do
+ source 'config.erb'
+ variables(
+ db_token: secret(name: 'db_token', service: :aws_secrets_manager)
+ )
+end
+```
diff --git a/content/infra_language/shelling_out.md b/content/infra_language/shelling_out.md
new file mode 100644
index 0000000..4e47e60
--- /dev/null
+++ b/content/infra_language/shelling_out.md
@@ -0,0 +1,36 @@
++++
+title = "Chef Infra Language: Shelling Out"
+draft = false
+
+[menu]
+ [menu.infra_language]
+ title = "Shelling Out"
+ identifier = "infra_language/shelling_out.md Shelling Out"
+ parent = "infra_language"
++++
+
+In most cases when you need to run a particular command in a cookbook, you'll want to use the [execute resource](/resources/bundled/execute/). Helper methods for shelling out can be useful when writing custom resources or other more advanced Ruby code.
+
+## shell_out
+
+The `shell_out` method can be used to run a command against the node, and then display the output to the console when the log level is set to `debug`.
+
+The syntax for the `shell_out` method is as follows:
+
+```ruby
+shell_out(command_args)
+```
+
+where `command_args` is the command that's run against the node.
+
+## shell_out!
+
+The `shell_out!` method can be used to run a command against the node, display the output to the console when the log level is set to `debug`, and then raise an error when the method returns `false`.
+
+The syntax for the `shell_out!` method is as follows:
+
+```ruby
+shell_out!(command_args)
+```
+
+where `command_args` is the command that's run against the node. This method will return `true` or `false`.
diff --git a/content/infra_language/windows.md b/content/infra_language/windows.md
new file mode 100644
index 0000000..5666355
--- /dev/null
+++ b/content/infra_language/windows.md
@@ -0,0 +1,32 @@
++++
+title = "Chef Infra Language: Windows"
+draft = false
+
+[menu]
+ [menu.infra_language]
+ title = "Windows"
+ identifier = "infra_language/windows.md Windows"
+ parent = "infra_language"
++++
+
+Chef Infra Client 15.8 and later include Windows-specific helpers for checking platform and package information.
+
+## windows_server_core?
+
+Determine if the current node is Windows Server Core.
+
+## windows_workstation?
+
+Determine if the current node is Windows Workstation.
+
+## windows_server?
+
+Determine if the current node is Windows Server.
+
+## windows_nt_version
+
+Determine the current Windows NT version. The NT version often differs from the marketing version, but offers a good way to find desktop and server releases that are based on the same codebase. For example NT 6.3 corresponds to Windows 8.1 and Windows 2012 R2.
+
+## powershell_version
+
+Determine the installed version of PowerShell.
diff --git a/content/install/_index.md b/content/install/_index.md
index a0d7255..981e617 100644
--- a/content/install/_index.md
+++ b/content/install/_index.md
@@ -2,10 +2,12 @@
title = "Install Chef Infra Client"
linkTitle = "Install"
-[menu.install]
-title = "Overview"
-parent = "install"
-weight = 10
+[menu]
+ [menu.install]
+ title = "Overview"
+ identifier = "install/overview"
+ parent = "install"
+ weight = 10
+++
Use either a native installer or the Chef Infra Client migration tool to install or upgrade Chef Infra Client.
@@ -28,7 +30,7 @@ The [Chef Infra Client migration tool](migration_tool) (`chef-migrate`) allows y
**Key functions:**
-- **Fresh installation:** Install Chef Infra Client 19 RC3
-- **Side-by-side installation:** Install Chef Infra Client 19 RC3 and remove or keep the previous Infra Client version. If you keep the previous version in side-by-side mode, the path to the most recent version takes precedence
+- **Fresh installation:** Install Chef Infra Client
+- **Side-by-side installation:** Install Chef Infra Client and remove or keep the previous Infra Client version. If you keep the previous version in side-by-side mode, the path to the most recent version takes precedence
- **Omnibus upgrade:** Upgrade from Omnibus-based Chef Infra Client 17.x or 18.x versions
-- **Habitat upgrade:** Upgrade from Habitat-packaged Chef Infra Client 19 RC releases
+- **Habitat upgrade:** Upgrade from Habitat-packaged Chef Infra Client releases
diff --git a/content/install/config_rb_client.md b/content/install/config_rb_client.md
new file mode 100644
index 0000000..35b2005
--- /dev/null
+++ b/content/install/config_rb_client.md
@@ -0,0 +1,591 @@
++++
+title = "client.rb"
+draft = false
+
+[menu]
+ [menu.install]
+ title = "client.rb"
+ identifier = "install/config_rb_client.md client.rb Configuration"
+ parent = "install"
+ weight = 50
++++
+
+
+
+{{< readfile file="content/reusable/md/config_rb_client_summary.md" >}}
+
+## Settings
+
+This configuration file has the following settings:
+
+`add_formatter`
+: A 3rd-party formatter. (See [nyan-cat](https://github.com/andreacampi/nyan-cat-chef-formatter) for an example of a 3rd-party formatter.) Each formatter requires its own entry.
+
+`allowed_automatic_attributes`
+: An array that allows `automatic` attributes, preventing non-allowed attributes from being saved.
+
+ For more information, see [Attribute Persistence](\{\{< relref "/cookbooks/attributes/attribute_persistence#attribute-allowlist" >}}).
+
+`allowed_default_attributes`
+: An array that allows `default` attributes, preventing non-allowed attributes from being saved.
+
+ For more information, see [Attribute Persistence](\{\{< relref "/cookbooks/attributes/attribute_persistence#attribute-allowlist" >}}).
+
+`allowed_normal_attributes`
+: An array that allows `normal` attributes, preventing non-allowed attributes from being saved.
+
+ For more information, see [Attribute Persistence](\{\{< relref "/cookbooks/attributes/attribute_persistence#attribute-allowlist" >}}).
+
+`allowed_override_attributes`
+: An array that allows `override` attributes, preventing non-allowed attributes from being saved.
+
+ For more information, see [Attribute Persistence](\{\{< relref "/cookbooks/attributes/attribute_persistence#attribute-allowlist" >}}).
+
+`authentication_protocol_version`
+: Sets the authentication protocol that's used to communicate with Chef Infra Server. For example, specify protocol version 1.3 to enable support for SHA-256 algorithms:
+
+ ```ruby
+ knife[:authentication_protocol_version] = '1.3'
+ ```
+
+ {{< note >}}
+
+ Authentication protocol 1.3 is only supported on Chef Infra Server versions 12.4.0 and above.
+
+ {{< /note >}}
+
+`automatic_attribute_blacklist`
+: **EOL in Chef Infra Client 18**. Use `blocked_automatic_attributes`.
+: An array that blocks `automatic` attributes, preventing blocked attributes from being saved.
+
+`automatic_attribute_whitelist`
+: **EOL in Chef Infra Client 18**. Use `allowed_automatic_attributes`.
+: An array that allows `automatic` attributes, preventing non-allowed attributes from being saved.
+
+`blocked_automatic_attributes`
+: An array that blocks `automatic` attributes, preventing blocked attributes from being saved.
+
+ For more information, see [Attribute Persistence](\{\{< relref "/cookbooks/attributes/attribute_persistence#attribute-blocklist" >}}).
+
+`blocked_default_attributes`
+: An array that blocks `default` attributes, preventing block attributes from being saved.
+
+ For more information, see [Attribute Persistence](\{\{< relref "/cookbooks/attributes/attribute_persistence#attribute-blocklist" >}}).
+
+`blocked_normal_attributes`
+: An array allows `normal` attributes, preventing non-allowed attributes from being saved.
+
+ For more information, see [Attribute Persistence](\{\{< relref "/cookbooks/attributes/attribute_persistence#attribute-blocklist" >}}).
+
+`blocked_override_attributes`
+: An array blocks `override` attributes, preventing blocked attributes from being saved.
+
+ For more information, see [Attribute Persistence](\{\{< relref "/cookbooks/attributes/attribute_persistence#attribute-blocklist" >}}).
+
+`cache_path`
+: The home directory for the user that runs Chef Infra Client as a non-root user.
+
+`checksum_path`
+: The location in which checksum files are stored. These are used to validate individual cookbook files, such as recipes. The checksum itself is stored in the Chef Infra Server database and is then compared to a file in the checksum path that has a filename identical to the checksum.
+
+`chef_guid`
+: The node UUID used by Chef Automate. Setting this allows the node UUID to be specified, and can be carried across instances of a node.
+
+`chef_license`
+: Used to accept the Chef license. Can be set to `accept` or `accept-no-persist`, which persists the license acceptance to disk. If passed to versions where the license isn't required this configuration option is a no-op.
+
+`chef_repo_path`
+: The path to the chef-repo containing cookbooks and other files, such as environments or data bags, when running Chef Infra Client in local mode.
+
+`chef_server_url`
+: The URL of Chef Infra Server. For example:
+
+ ```ruby
+ https://localhost/organizations/ORG_NAME
+ ```
+
+`chef_zero.enabled`
+: Enable chef-zero. This setting requires `local_mode` to be set to `true`.
+
+ Default value: `true` if running in local-mode, otherwise `false`.
+
+`chef_zero.port`
+: The port on which chef-zero is to listen. If specified as a range, Chef Infra Client will take the first available port in the range. For example `10,20,30` or `10000-20000`.
+
+ Default value: `8889-9999`.
+
+`clear_gem_sources`
+: Globally sets the default of the `clear_sources` property on the `gem_package` and `chef_gem` resources.
+
+ Default value: `false`.
+
+`client_fork`
+: Contain Chef Infra Client runs in a secondary process with dedicated RAM. When a Chef Infra Client run is complete, the RAM is returned to the parent process. This setting helps ensure that a Chef Infra Client uses a steady amount of RAM over time because the parent process doesn't run recipes. This setting also helps prevent memory leaks such as those that can be introduced by the code contained within a poorly designed cookbook.
+
+ Default value: `true`. Set to `false` to disable running Chef Infra Client in fork node.
+
+ {{< note >}}
+
+ Must be set to `false` up to Chef Infra Client 13.11.3 to gather the standard return code offered by `exit_status true`. Later versions run as expected without changes to the configuration file.
+
+ {{< /note >}}
+
+`client_key`
+: The location of the file that contains the client key.
+
+ Default value: `/etc/chef/client.pem`.
+
+`client_registration_retries`
+: The number of times a Chef Infra Client will attempt to register with a Chef Infra Server.
+
+ Default value: `5`.
+
+`client_d_dir`
+: A directory that contains additional configuration files for Chef Infra Client.
+
+`cookbook_path`
+: The sub-directory for Chef Infra Client cookbooks. This value can be a string or an array of file system locations, processed in the specified order. The last cookbook is considered to override local modifications.
+
+`cookbook_sync_threads`
+: The number of helper threads available for parallel cookbook synchronization. Increasing this value **may** increase the frequency of gateway errors from Chef Infra Server (503 and 504 errors). Decreasing this number reduces the frequency of gateway errors, if present.
+
+ Default value: `10`.
+
+`data_bag_decrypt_minimum_version`
+: The minimum required version of data bag encryption. Possible values: `1`, `2`, and `3`.
+ Use the default value of `3` for additional encrypted data bag security.
+
+`data_bag_path`
+: The location from which a data bag is loaded.
+
+ Default value: `/var/chef/data_bags`.
+
+`data_collector.server_url`
+: The fully qualified URL to the data collector server API.
+
+`data_collector.token`
+: The shared data collector security token. When configured, the token will be passed as an HTTP header named `x-data-collector-token` which the server can choose to accept or reject.
+
+`data_collector.mode`
+: The Chef Infra Client mode in which the Data Collector will be enabled. Possible values: `:solo`, `:client`, or `:both`. The `:solo` value is used for Chef Infra Client operating in Chef Solo Mode or Chef Solo Legacy Mode.
+
+ Default value: `both`.
+
+`data_collector.raise_on_failure`
+: When enabled, Chef Infra Client raises an error if it can't successfully POST to the data collector server.
+
+ Default value: `false`.
+
+`default_attribute_blacklist`
+: **EOL in Chef Infra Client 18**. Use `blocked_default_attributes`.
+: Normal that blocks `default` attributes, preventing block attributes from being saved.
+
+`default_attribute_whitelist`
+: **EOL in Chef Infra Client 18**. Use `allowed_default_attributes`.
+: Normal that allows `default` attributes, preventing non-allowed attributes from being saved.
+
+`diff_disabled`
+: Cause Chef Infra Client to create a diff when changes are made to a file.
+
+ Default value: `false`.
+
+`diff_filesize_threshold`
+: The maximum size (in bytes) of a file for which Chef Infra Client can create a diff.
+
+ Default value: `10000000`.
+
+`diff_output_threshold`
+: The maximum size (in bytes) of a diff file Chef Infra Client can create.
+
+ Default value: `1000000`.
+
+`disable_event_logger`
+: Enable or disable sending Chef Infra Client internal state events to the Windows "Application" event log. Set to `false` to send events to the Windows "Application" event log at the start and end of a Chef Infra Client run, and also if a Chef Infra Client run fails. Use `log_location` to set the destination of your Chef Infra Client logs to the Windows event log. Set to `true` to disable event logging.
+
+ Default value: `false`.
+
+`enable_reporting`
+: Cause Chef Infra Client to send run data to Chef Automate server.
+
+ Default value: `true`
+
+`enable_reporting_url_fatals`
+: Cause a Chef Infra Client run to fail when run data can't be sent to the Chef Automate server (for any reason).
+
+ Default value: `false`
+
+`enable_selinux_file_permission_fixup`
+: SELinux environments only. Cause Chef Infra Client to attempt to apply the correct file permissions to an updated file using the `restorecon` command. Set to `false` to prevent Chef Infra Client from attempting this action.
+
+`encrypted_data_bag_secret`
+: The path to a secrets file which can decrypt encrypted data bags.
+
+`enforce_default_paths`
+: Turn on path sanity in resources that shellout so that expected paths like `/sbin` or `/bin` are added to the PATH.
+
+ Disabled by default.
+
+`enforce_path_sanity`
+: **EOL in Chef Infra Client 18**. Use `enforce_default_paths`.
+: Turn on path sanity in resources that shellout so that expected paths like `/sbin` or `/bin` are added to the PATH.
+
+ Disabled by default.
+
+`environment`
+: The name of the Chef Infra environment.
+
+`environment_path`
+: The path to the environment file.
+
+ Default value: `/var/chef/environments`.
+
+`exit_status`
+: When set to `:enabled`, Chef Infra Client will use [standardized exit codes](https://github.com/chef/chef/blob/main/docs/dev/design_documents/client_exit_codes.md#exit-codes-in-use) for the Chef Infra Client run status, and any non-standard exit codes will be converted to `1` or `GENERIC_FAILURE`.
+ This setting can also be set to `:disabled` to use the pre-Chef Infra Client 13 exit code behavior.
+
+ Default value: `nil`.
+
+`file_atomic_update`
+: Apply atomic file updates to all resources. Set to `true` for global atomic file updates. Set to `false` for global non-atomic file updates. (Use the `atomic_update` setting for each resource to override this setting.)
+
+ Default value: `true`.
+
+ {{< warning >}}
+
+ Changing this setting to `false` may cause file corruption, data loss, or instability. Use the `atomic_update` property on the **cookbook_file**, **file**, **remote_file**, and **template** resources to tune this behavior at the recipe level.
+
+ {{< /warning >}}
+
+`file_backup_path`
+: The location in which backup files are stored. If this value is empty, backup files are stored in the directory of the target file.
+
+ Default value: `/var/chef/backup`.
+
+`file_cache_path`
+: The location in which cookbooks (and other transient data) files are stored when they're synchronized. This value can also be used in recipes to download files with the **remote_file** resource.
+
+`file_staging_uses_destdir`
+: How file staging (using temporary files) is done. When `true`, temporary files are created in the directory in which files will reside. When `false`, temporary files are created under `ENV['TMP']`.
+
+ Default value: `true`.
+
+`fips`
+: Allows OpenSSL to enforce FIPS-validated security during a Chef Infra Client run. Set to `true` to enable FIPS-validated security.
+
+`force_formatter`
+: Using `force_formatter` makes Chef Infra Client default to formatter output when STDOUT isn't a TTY.
+
+`force_logger`
+: Using `force_logger` makes Chef Infra Client default to logger output when STDOUT is a TTY.
+
+`ftp_proxy`
+: The proxy server for FTP connections.
+
+`ftp_proxy_pass`
+: The password for the proxy server when the proxy server is using an FTP connection.
+
+ Default value: `nil`.
+
+`ftp_proxy_user`
+: The user name for the proxy server when the proxy server is using an FTP connection.
+
+ Default value: `nil`.
+
+`group`
+: The group that owns a process. This is required when starting any executable as a daemon.
+
+ Default value: `nil`.
+
+`gem_installer_bundler_options`
+: Additional options to pass to bundler when installing metadata for cookbook.
+
+ Default value: `nil`.
+
+ For example:
+
+ ```ruby
+ gem_installer_bundler_options = [
+ "--local", "--clean"
+ ]
+ ```
+
+ or
+
+ ```ruby
+ gem_installer_bundler_options = "--local"
+ ```
+
+`http_proxy`
+: The proxy server for HTTP connections.
+
+ Default value: `nil`.
+
+`http_proxy_pass`
+: The password for the proxy server when the proxy server is using a HTTP connection.
+
+ Default value: `nil`.
+
+`http_proxy_user`
+: The user name for the proxy server when the proxy server is using a HTTP connection.
+
+ Default value: `nil`.
+
+`http_retry_count`
+: The number of retry attempts.
+
+ Default value: `5`.
+
+`http_retry_delay`
+: The delay (in seconds) between retry attempts.
+
+ Default value: `5`.
+
+`https_proxy`
+: The proxy server for HTTPS connections.
+
+ Default value: `nil`.
+
+`https_proxy_pass`
+: The password for the proxy server when the proxy server is using a HTTPS connection.
+
+ Default value: `nil`.
+
+`https_proxy_user`
+: The user name for the proxy server when the proxy server is using a HTTPS connection.
+
+ Default value: `nil`.
+
+`interval`
+: The frequency (in seconds) at which Chef Infra Client runs when running in daemonized mode. We don't recommend running in daemonized mode. Instead you should rely on scheduled execution from system schedulers like systemd timers, cron jobs, or Windows Scheduled Tasks.
+
+ Default value: `1800`.
+
+`json_attribs`
+: The path to a file that contains JSON data.
+
+`listen`
+: Run chef-zero in socketless mode. Set to `false` to disable port binding and HTTP requests on localhost.
+
+`local_key_generation`
+: Whether Chef Infra Server or Chef Infra Client generates the private/public key pair. When `true`, Chef Infra Client generates the key pair, and then sends the public key to Chef Infra Server.
+
+ Default value: `true`.
+
+`local_mode`
+: Run Chef Infra Client in local mode. This allows all commands that work against Chef Infra Server to also work against the local chef-repo.
+
+`lockfile`
+: The location of the Chef Infra Client lock file. This value is typically platform dependent, so it should be a location defined by `file_cache_path`. The default location of a lock file shouldn't be on an NFS mount.
+
+ Default value: a location defined by `file_cache_path`.
+
+`log_level`
+: The level of logging to be stored in a log file. Possible levels: `:auto` (default), `:trace`, `:debug`, `:info`, `:warn`, `:error`, or `:fatal`. The `:auto` level will use `:warn` when a terminal is available or `:info` when a terminal isn't available.
+
+`log_location`
+: The location of the log file. Possible values: `/path/to/log_location`, `STDOUT`, `STDERR`, `:win_evt` (Windows Event Logger), or `:syslog` (writes to the syslog daemon facility with the originator set as `chef-client`). The application log will specify the source as `Chef`.
+
+ Default value: `STDOUT`.
+
+`migrate_key_to_keystore`
+: Set to `true` to tell the Chef Infra Client to create a new key pair in a PFX certificate object and store that in the local machine certificate store. Chef Infra Client will check for the presence of that key when the headers to connect to Chef Infra Server are built and will use it if present. **Windows only.**
+
+`minimal_ohai`
+: Run a minimal set of Ohai plugins providing data necessary for the execution of Chef Infra Client's built-in resources. Setting this to true will skip many large and time consuming plugins such as `cloud` or `packages`. Setting this to true may break cookbooks that assume all Ohai data will be present.
+
+`named_run_list`
+: A specific named runlist defined in the node's applied Policyfile which should be used when running Chef Infra Client.
+
+`no_lazy_load`
+: Download all cookbook files and templates at the beginning of a Chef Infra Client run.
+
+ Default value: `true`.
+
+`no_proxy`
+: A comma-separated list of URLs that don't need a proxy.
+
+ Default value: `nil`.
+
+`node_name`
+: The unique identifier of the node. This determines which configuration should be applied and sets the `client_name`, which is the name used when authenticating to a Chef Infra Server. By default, Chef Infra Client will use the system's FQDN as the node name. In general, Chef recommends that you leave this setting blank and let the client assign the FQDN of the node as the `node_name` during each Chef Infra Client run.
+
+`node_path`
+: The location in which nodes are stored during a Chef Infra Client run in local mode.
+
+ Default value: `/var/chef/node`.
+
+`normal_attribute_blacklist`
+: **EOL in Chef Infra Client 18**. Use `blocked_normal_attributes`.
+: An array that blocks `normal` attributes, preventing blocked attributes from being saved.
+
+`override_attribute_blacklist`
+: **EOL in Chef Infra Client 18**. Use `blocked_override_attributes`.
+: An array that blocks `override` attributes, preventing blocked attributes from being saved.
+
+`normal_attribute_whitelist`
+: **EOL in Chef Infra Client 18**. Use `allowed_normal_attributes`.
+: An array that allows `normal` attributes, preventing non-allowed attributes from being saved.
+
+`override_attribute_whitelist`
+: **EOL in Chef Infra Client 18**. Use `allowed_override_attributes`.
+: An array that allows `override` attributes, preventing non-allowed attributes from being saved.
+
+`pid_file`
+: The location in which a process identification number (pid) is saved. An executable, when started as a daemon, writes the pid to the specified file.
+
+ Default value: `/tmp/name-of-executable.pid`.
+
+`policy_group`
+: The name of a policy group that exists on Chef Infra Server. `policy_name` must also be specified.
+
+`policy_group_path`
+: The location of policy_groups on disk.
+
+`policy_name`
+: The name of a policy, as identified by the `name` setting in a Policyfile.rb file. `policy_group` must also be specified.
+
+`policy_path`
+: The location of policies on disk.
+
+`recipe_url`
+: A URL to download recipes from when running in local mode.
+
+`rest_timeout`
+: The time (in seconds) after which an HTTP REST request is to time out.
+
+ Default value: `300`.
+
+`role_path`
+: The location in which role files are located.
+
+ Default value: `/var/chef/roles`.
+
+`rubygems_url`
+: The location to source rubygems. It can be set to a string or array of strings for URIs to set as rubygems sources. This allows individuals to setup an internal mirror of rubygems for "airgapped" environments.
+
+ Default value: `https://www.rubygems.org`. If a `source` is specified in either `gem_package` of `chef_gem` resources it will be added to the values provided here.
+
+`run_lock_timeout`
+: The amount of time (in seconds) to wait for a Chef Infra Client lock file to be deleted.
+ A Chef Infra Client run won't start when a lock file is present.
+ If a lock file isn't deleted before this time expires, the pending Chef Infra Client run exits.
+
+ Default value: not set (indefinite). Set to `0` to cause a second Chef Infra Client to exit immediately.
+
+`script_path`
+: An array of paths to search for knife exec scripts if they're not in the current directory
+
+`skip_gem_metadata_installation`
+: when `skip_gem_metadata_installation` is set to true, cookbook gem installation will be skipped.
+
+ Default value: `false`
+
+`splay`
+: A random number between zero and `splay` that's added to `interval`. Use splay to help balance the load on Chef Infra Server by ensuring that many Chef Infra Client runs aren't occurring at the same interval.
+
+ Default value: `nil`.
+
+`stream_execute_output`
+: Always stream the output of `execute` resources even if the `live_stream` property isn't set to true.
+
+ Default value: `false`
+
+`show_download_progress`
+: Using show_download_progress will display the overall progress of a `remote_file` download.
+
+ Default value: `false`
+
+`download_progress_interval`
+: When `show_download_progress` is set to true this is the interval in seconds to write out download progress.
+
+ Default value: `10`
+
+`ssl_ca_file`
+: The file in which the OpenSSL key is saved. Chef Infra Client generates this setting automatically and most users don't need to modify it.
+
+`ssl_ca_path`
+: The path to where the OpenSSL key is located. Chef Infra Client generates this setting automatically and most users don't need to modify it.
+
+`ssl_client_cert`
+: The OpenSSL X.509 certificate used for mutual certificate validation. This setting is only necessary when mutual certificate validation is configured on Chef Infra Server.
+
+ Default value:`nil`.
+
+`ssl_client_key`
+: The OpenSSL X.509 key used for mutual certificate validation. This setting is only necessary when mutual certificate validation is configured on Chef Infra Server.
+
+ Default value: `nil`.
+
+`ssl_verify_mode`
+: Set the verify mode for HTTPS requests.
+
+ - Use `:verify_none` for no validation of SSL certificates.
+ - Use `:verify_peer` for validation of all SSL certificates, including Chef Infra Server connections, S3 connections, and any HTTPS **remote_file** resource URLs used in Chef Infra Client runs. This is the recommended setting.
+
+ Depending on how OpenSSL is configured, the `ssl_ca_path` may nee to be specified.
+
+ Default value: `:verify_peer`.
+
+`trusted_certs_dir`
+: A directory that contains additional SSL certificates to trust. Any certificates in this directory will be added to whatever CA bundle ruby is using.
+ Use this to add self-signed certs for your Chef Infra Server or local HTTP file servers.
+
+ Default value: `trusted_certs` directory in your chef configuration directory.
+
+`umask`
+: The file mode creation mask, or umask.
+
+ Default value: `0022`.
+
+`use_policyfile`
+: Chef Infra Client automatically checks the configuration, node JSON, and the stored node on Chef Infra Server to determine if Policyfile files are in use, and then automatically updates this flag.
+
+ Default value: `false`.
+
+`user`
+: The user that owns a process. This is required when starting any executable as a daemon.
+
+ Default value: `nil`.
+
+`validation_client_name`
+: The name of the chef-validator key that Chef Infra Client uses to access Chef Infra Server during the initial Chef Infra Client run. This is only used by the legacy validator based bootstrapping.
+
+`validation_key`
+: The location of the file that contains the key used when a Chef Infra Client is registered with a Chef Infra Server. A validation key is signed using the `validation_client_name` for authentication.
+
+ Default value: `/etc/chef/validation.pem`. This is only used by the legacy validator based bootstrapping.
+
+`verbose_logging`
+: Set the log level. Options: `true`, `nil`, and `false`. When this is set to `false`, notifications about individual resources being processed are suppressed (and are output at the `:info` logging level). Setting this to `false` can be useful when a Chef Infra Client is run as a daemon.
+
+ Default value: `nil`.
+
+`verify_api_cert`
+: Verify the SSL certificate on Chef Infra Server. When `true`, Chef Infra Client always verifies the SSL certificate. When `false`, Chef Infra Client uses the value of `ssl_verify_mode` to determine if the SSL certificate requires verification.
+
+ Default value: `false`.
+
+### Automatic Proxy Config
+
+{{< readfile file="content/reusable/md/proxy_env.md" >}}
+
+## .d Directories
+
+{{< readfile file="content/reusable/md/config_rb_client_dot_d_directories.md" >}}
+
+## Ohai Settings
+
+{{< readfile file="content/reusable/md/config_rb_ohai.md" >}}
+
+{{< readfile file="content/reusable/md/config_rb_ohai_settings.md" >}}
+
+## Example
+
+The following `client.rb` file shows the simplest way to connect to Chef Infra Server:
+
+```ruby
+chef_server_url 'https://chef-server.example.com/organizations/ORGANIZATION'
+validation_client_name '-validator'
+validation_key '/etc/chef/validator.pem'
+client_key '/etc/chef/client.pem'
+```
diff --git a/content/install/install_bootstrap.md b/content/install/install_bootstrap.md
new file mode 100644
index 0000000..550c649
--- /dev/null
+++ b/content/install/install_bootstrap.md
@@ -0,0 +1,457 @@
++++
+title = "Bootstrap a node"
+draft = false
+
+[menu]
+ [menu.install]
+ title = "Install using Bootstrap"
+ identifier = "install/install_bootstrap.md Install using Bootstrap"
+ parent = "install"
+ weight = 40
++++
+
+{{< readfile file="content/reusable/md/chef_client_bootstrap_node.md" >}}
+
+{{< readfile file="content/reusable/md/chef_client_bootstrap_stages.md" >}}
+
+## knife bootstrap
+
+{{< readfile file="content/reusable/md/install_chef_client.md" >}}
+
+### Run the bootstrap command
+
+The `knife bootstrap` command runs a bootstrap operation that installs Chef Infra Client on a target node. The following steps describe how to bootstrap a node using knife.
+
+1. Identify the FQDN or IP address of the target node. The `knife bootstrap` command requires the FQDN or the IP address for the node to complete the bootstrap operation.
+
+2. Once the workstation machine is configured, it can be used to install Chef Infra Client on one (or more) nodes across the organization using a knife bootstrap operation. The `knife bootstrap` command is used to SSH into the target machine, and then do what's needed to allow Chef Infra Client to run on the node. It will install the Chef Infra Client executable (if necessary), generate keys, and register the node with Chef Infra Server. The bootstrap operation requires the IP address or FQDN of the target system, the SSH credentials (username, password or identity file) for an account that has root access to the node, and (if the operating system isn't Ubuntu, which is the default distribution used by `knife bootstrap`) the operating system running on the target system.
+
+ In a command window, enter the following:
+
+ ```bash
+ knife bootstrap -U --sudo
+ ```
+
+ Replace:
+
+ - `` the IP address or the FQDN of the node
+ - `` with the username used to connect to the node
+
+ The `--sudo` option elevates privileges using the sudo command on UNIX-based systems.
+
+ While the bootstrap operation is running, the command window returns something similar to the following:
+
+ ```bash
+ Enter password for ubuntu@172.16.1.233:
+
+ Connecting to 172.16.1.233
+ Performing legacy client registration with the validation key at /Users/USERNAME/.chef/validator.pem...
+ Delete your validation key to use your user credentials for client registration instead.
+ Bootstrapping 172.16.1.233
+ [172.16.1.233] -----> Installing Chef Omnibus (stable/16)
+ downloading https://omnitruck.chef.io/chef/install.sh
+ [172.16.1.233] to file /tmp/install.sh.1624/install.sh
+ [172.16.1.233] trying wget...
+ [172.16.1.233] ubuntu 20.04 aarch64
+ [172.16.1.233] Getting information for chef stable 16 for ubuntu...
+ [172.16.1.233] downloading https://omnitruck.chef.io/stable/chef/metadata?v=16&p=ubuntu&pv=20.04&m=aarch64
+ to file /tmp/install.sh.1628/metadata.txt
+ [172.16.1.233] trying wget...
+ [172.16.1.233] sha1 8d89f8ac2e7f52d170be8ec1c2a028a6449d7e3a
+ sha256 85cc73bed06e8d6699fc5c0b26c20d2837bf03831873444febccfc8bfa561f00
+ url https://packages.chef.io/files/stable/chef/16.1.16/ubuntu/20.04/chef_16.1.16-1_arm64.deb
+ version 16.1.16
+ [172.16.1.233]
+ [172.16.1.233] downloaded metadata file looks valid...
+ [172.16.1.233] downloading https://packages.chef.io/files/stable/chef/16.1.16/ubuntu/20.04/chef_16.1.16-1_arm64.deb
+ to file /tmp/install.sh.1628/chef_16.1.16-1_arm64.deb
+ [172.16.1.233] trying wget...
+ [172.16.1.233] Comparing checksum with sha256sum...
+ [172.16.1.233] Installing chef 16
+ installing with dpkg...
+ [172.16.1.233] Selecting previously unselected package chef.
+ [172.16.1.233] (Reading database ... 99114 files and directories currently installed.)
+ [172.16.1.233] Preparing to unpack .../chef_16.1.16-1_arm64.deb ...
+ [172.16.1.233] Unpacking chef (16.1.16-1) ...
+ [172.16.1.233] Setting up chef (16.1.16-1) ...
+ [172.16.1.233] Thank you for installing Chef Infra Client! For help getting started visit https://learn.chef.io
+ [172.16.1.233] Starting the first Chef Infra Client Client run...
+ [172.16.1.233] +---------------------------------------------+
+ ✓ 2 product licenses accepted.
+ +---------------------------------------------+
+ [172.16.1.233] Starting Chef Infra Client, version 16.1.16
+ [172.16.1.233] [2020-06-08T23:49:10+00:00] ERROR: shard_seed: Failed to get dmi property serial_number: is dmidecode installed?
+ [172.16.1.233] Creating a new client identity for name_of_node using the validator key.
+ [172.16.1.233] resolving cookbooks for run list: []
+ [172.16.1.233] Synchronizing Cookbooks:
+ [172.16.1.233] Installing Cookbook Gems:
+ [172.16.1.233] Compiling Cookbooks...
+ [172.16.1.233] [2020-06-08T23:49:17+00:00] WARN: Node name_of_node has an empty run list.
+ [172.16.1.233] Converging 0 resources
+ [172.16.1.233]
+ [172.16.1.233] Running handlers:
+ [172.16.1.233] Running handlers complete
+ [172.16.1.233] Chef Infra Client finished, 0/0 resources updated in 11 seconds
+ ```
+
+3. After the bootstrap operation has finished, verify that the node is recognized by Chef Infra Server. To show only the node that was just bootstrapped, run the following command:
+
+ ```bash
+ knife client show NAME_OF_NODE
+ ```
+
+ where `NODE_NAME` is the name of the node that was just bootstrapped. Chef Infra Server will return something similar to:
+
+ ```bash
+ admin: false
+ chef_type: client
+ name: NODE_NAME
+ validator: false
+ ```
+
+ and to show the full list of nodes (and workstations) that are registered with Chef Infra Server, run the following command:
+
+ ```bash
+ knife client list
+ ```
+
+ Chef Infra Server will return something similar to:
+
+ ```bash
+ workstation1
+ workstation2
+ ...
+ client1
+ client2
+ ```
+
+## Validatorless and legacy validator bootstraps
+
+We recommended using "validatorless bootstrapping" to authenticate new nodes with Chef Infra Server.
+
+The legacy Chef Infra validator-based node bootstrapping process depended on using a shared "validatory" key throughout an organization for authenticating new nodes with Chef Infra Server.
+
+Shortcomings of the legacy validator process are:
+
+- All users share the same key for bootstrapping new systems
+- Key sharing makes key rotation difficult, if it's compromised or if an employee leaves the organization.
+
+The "validatorless bootstrap" generates a key for each node, which is then transferred to the new node and used to authenticate with Chef Infra Server instead of relying on a shared "validator" key.
+
+The Chef Infra bootstrap process is validatorless by default. If you receive a warning during a bootstrap that a validator key is in use, remove the configuration for this legacy bootstrap mode. Edit your [config.rb (knife.rb)](https://docs.chef.io/workstation/config_rb/) file and remove any `validation_key` or `validation_client_name` entries.
+
+## Bootstrapping with chef-vault
+
+Use the following options with a validatorless bootstrap to specify items that are stored in chef-vault:
+
+`--bootstrap-vault-file VAULT_FILE`
+
+: The path to a JSON file that contains a list of vaults and items to be updated.
+
+`--bootstrap-vault-item VAULT_ITEM`
+
+: A single vault and item to update as `vault:item`.
+
+`--bootstrap-vault-json VAULT_JSON`
+
+: A JSON string that contains a list of vaults and items to be updated. `--bootstrap-vault-json '{ "vault1": \["item1", "item2"\], "vault2": "item2" }'`
+
+## Examples
+
+The `--bootstrap-vault-*` options add the client identify of the bootstrapping node to the permissions list of the specified vault item. This enables the newly-bootstrapped Chef Infra Client to be able to read items from the vault. Only a single client is authorized at a time for access to the vault. (The `-S` search query option with the `knife vault create` subcommand does the same.)
+
+### Recreate a data bag item
+
+The following example shows how to recreate a data bag item:
+
+```bash
+knife vault delete sea power
+Do you really want to delete sea/power? (Y/N) Y
+Deleted chef_vault_item[sea/power]
+
+echo "{\"some\":\"content for them\"}" > sea-power-content.json
+
+cat sea-power-content.json
+{"some":"content for them"}
+
+knife vault create sea power -M client -A sean_horn,angle -J sea-power-content.json
+```
+
+No clients, because the `-S` option wasn't specified while creating the vault.
+
+At this time, only the users `sean_horn` and `angle` are authorized to read and manage the vault.
+
+```bash
+knife vault show sea power --mode client -p all
+admins:
+ sean_horn
+ angle
+clients:
+id: power
+search_query:
+some: content for them
+```
+
+It's definitely an encrypted databag, see?
+
+```bash
+knife data_bag show sea power
+WARNING: Encrypted data bag detected, but no secret provided for decoding. Displaying encrypted data.
+id: power
+some:
+cipher: aes-256-cbc
+encrypted_data: c7Axnyg+1KDxBPOZdYN9QuIYx6dmSmK70unAQbn12Lygvsv2g9DPJJbueXVh
++yxL
+iv: ONoVR7OjPZiAzaqOZ30bjg==
+version: 1
+```
+
+### Use --bootstrap-vault-file
+
+Use the `sea:power` recreation step above first, to follow the difference in the vault permissions.
+
+```bash
+echo "{\"sea\":\"power\"}" > sea-power-bootstrap-vault-file.json
+
+knife bootstrap localhost -p 2200 -N ubuntu-20.04 -r 'role[group1]' --connection-user vagrant --sudo --bootstrap-vault-file sea-power-bootstrap-vault-file.json
+Node ubuntu-20.04 exists, overwrite it? (Y/N) Y
+Client ubuntu-20.04 exists, overwrite it? (Y/N) Y
+Creating new client for ubuntu-20.04
+Creating new node for ubuntu-20.04
+Connecting to localhost
+localhost -----> Existing Chef installation detected
+localhost Starting first Chef Infra Client run...
+localhost Starting Chef Infra Client, version 12.2.1
+localhost resolving cookbooks for run list: ["delay-test-reporting"]
+localhost Synchronizing Cookbooks:
+localhost - delay-test-reporting
+localhost Compiling Cookbooks...
+localhost Converging 1 resources
+localhost Recipe: delay-test-reporting::default
+localhost * execute[sleep 30] action run
+localhost - execute sleep 30
+localhost
+localhost Running handlers:
+localhost Running handlers complete
+localhost Chef Infra Client finished, 1/1 resources updated in 34.307257232 seconds
+```
+
+The client `ubuntu-20.04` was added to the `chef-vault` during the bootstrap.
+
+```bash
+knife vault show sea power --mode client -p all
+admins:
+ sean_horn
+ angle
+clients: ubuntu-20.04
+id: power
+search_query:
+some: content for them
+```
+
+### Use --bootstrap-vault-item
+
+Use the `sea:power` re-creation step above first, to follow the difference in the vault permissions.
+
+```bash
+knife bootstrap localhost -p 2200 -N ubuntu-20.04 -r 'role[group1]' --connection-user vagrant --sudo --bootstrap-vault-item sea:power
+Node ubuntu-20.04 exists, overwrite it? (Y/N) Y
+Client ubuntu-20.04 exists, overwrite it? (Y/N) Y
+Creating new client for ubuntu-20.04
+Creating new node for ubuntu-20.04
+Connecting to localhost
+localhost -----> Existing Chef installation detected
+localhost Starting first Chef Infra Client run...
+localhost Starting Chef Infra Client, version 12.2.1
+localhost resolving cookbooks for run list: ["delay-test-reporting"]
+localhost Synchronizing Cookbooks:
+localhost - delay-test-reporting
+localhost Compiling Cookbooks...
+localhost Converging 1 resources
+localhost Recipe: delay-test-reporting::default
+localhost * execute[sleep 30] action run
+localhost - execute sleep 30
+localhost
+localhost Running handlers:
+localhost Running handlers complete
+localhost Chef Infra Client finished, 1/1 resources updated in 34.322229474
+seconds
+```
+
+During the above run, the `sea:power` vault item was updated with the `ubuntu-20.04` client during the validatorless bootstrap. Previously, it only had the two admins authorized to view the content
+
+```bash
+knife vault show sea power -p all
+admins:
+ sean_horn
+ angle
+clients: ubuntu-20.04
+id: power
+search_query: role:stuff
+some: secret stuff for them
+```
+
+Then, let's check the `ubuntu-20.04` client. The client itself can decrypt and read the encrypted databag contents as well using the embedded knife CLI in the Chef Infra Client package.
+
+```bash
+sudo /opt/chef/bin/knife vault show sea power -c /etc/chef/client.rb -M client -p all
+admins:
+ sean_horn
+ angle
+clients: ubuntu-20.04
+id: power
+search_query: role:group1
+some: secret stuff for them
+```
+
+Success! The client is authorized to view the content of the `sea:power` databag item
+
+### Use --bootstrap-vault-json
+
+Use the `sea:power` re-creation step above first, to follow the difference in the vault permissions.
+
+```bash
+knife bootstrap localhost -p 2200 -N ubuntu-20.04 -r 'role[group1]' --connection-user vagrant --sudo --bootstrap-vault-json '{"sea": "power"}'
+Node ubuntu-20.04 exists, overwrite it? (Y/N) Y
+Client ubuntu-20.04 exists, overwrite it? (Y/N) Y
+Creating new client for ubuntu-.04
+Creating new node for ubuntu-20.04
+Connecting to localhost
+localhost -----> Existing Chef installation detected
+localhost Starting first Chef Infra Client run...
+localhost Starting Chef Infra Client, version 12.2.1
+localhost resolving cookbooks for run list: ["delay-test-reporting"]
+localhost Synchronizing Cookbooks:
+localhost - delay-test-reporting
+localhost Compiling Cookbooks...
+localhost Converging 1 resources
+localhost Recipe: delay-test-reporting::default
+
+localhost * execute[sleep 30] action run
+localhost - execute sleep 30
+localhost
+localhost Running handlers:
+localhost Running handlers complete
+localhost Chef Infra Client finished, 1/1 resources updated in 33.732784033 seconds
+```
+
+```bash
+knife vault show sea power -M client -p all
+admins:
+ sean_horn
+ angle
+clients: ubuntu-20.04
+id: power
+search_query:
+some: content for them
+```
+
+## Unattended installs
+
+Chef Infra Client can be installed using an unattended bootstrap. This allows Chef Infra Client to be installed from itself, without requiring SSH. For example, machines are often created using environments like AWS Auto Scaling, AWS CloudFormation, Rackspace Auto Scale, and PXE. In this scenario, using tooling for attended, single-machine installs like `knife bootstrap` or `knife CLOUD_PLUGIN create` isn't practical because the machines are created automatically and someone can't always be on-hand to initiate the bootstrap process.
+
+When Chef Infra Client is installed using an unattended bootstrap, remember that Chef Infra Client:
+
+- Must be able to authenticate to Chef Infra Server.
+- Must be able to configure a run-list.
+- May require custom attributes, depending on the cookbooks that are being used.
+- Must be able to access the `chef-validator.pem` file so that it may create a new identity on Chef Infra Server.
+- Must have a unique node name; Chef Infra Client will use the FQDN for the host system by default.
+
+When Chef Infra Client is installed using an unattended bootstrap, it may be built into an image that starts Chef Infra Client on boot, or installed using User Data or some other kind of post-deployment script. The type of image or User Data used depends on the platform on which the unattended bootstrap will take place.
+
+### Bootstrapping with user data
+
+The method used to inject a user data script into a server varies depending on the infrastructure platform being used.
+For example, on AWS you can pass this data in as a text file using the command line.
+
+The following user data examples demonstrate the process of bootstrapping Windows and Linux nodes.
+
+#### PowerShell user data
+
+```powershell
+## Set host file so the instance knows where to find chef-server
+$hosts = "1.2.3.4 hello.example.com"
+$file = "C:\Windows\System32\drivers\etc\hosts"
+$hosts | Add-Content $file
+
+## Download Chef Infra Client
+$clientURL = "https://chefdownload-commercial.chef.io/stable/client/download?p=windows>&pv=&m=&v=&license_id="
+$clientDestination = "C:\chef-client.msi"
+Invoke-WebRequest $clientURL -OutFile $clientDestination
+
+## Install the Chef Infra Client
+Start-Process msiexec.exe -ArgumentList @('/qn', '/lv C:\Windows\Temp\chef-log.txt', '/i C:\chef-client.msi', 'ADDLOCAL="ChefClientFeature,ChefSchTaskFeature,ChefPSModuleFeature"') -Wait
+
+## Create first-boot.json
+$firstboot = @{
+ "run_list" = @("role[base]")
+}
+Set-Content -Path c:\chef\first-boot.json -Value ($firstboot | ConvertTo-Json -Depth 10)
+
+## Create client.rb
+$nodeName = "lab-win-{0}" -f (-join ((65..90) + (97..122) | Get-Random -Count 4 | % {[char]$_}))
+
+$clientrb = @"
+chef_server_url 'https://chef-server/organizations/my-org'
+validation_client_name 'validator'
+validation_key 'C:\chef\validator.pem'
+node_name '{0}'
+"@ -f $nodeName
+
+Set-Content -Path c:\chef\client.rb -Value $clientrb
+
+## Run Chef
+C:\opscode\chef\bin\chef-client.bat -j C:\chef\first-boot.json
+```
+
+#### Bash user data
+
+```bash
+#!/bin/bash -xev
+
+# Do some chef pre-work
+/bin/mkdir -p /etc/chef
+/bin/mkdir -p /var/lib/chef
+/bin/mkdir -p /var/log/chef
+
+# Setup hosts file correctly
+cat >> "/etc/hosts" << EOF
+10.0.0.5 compliance-server compliance-server.automate.com
+10.0.0.6 infra-server infra-server.automate.com
+10.0.0.7 automate-server automate-server.automate.com
+EOF
+
+cd /etc/chef/
+
+# Install chef
+curl -L https://omnitruck.chef.io/install.sh | bash || error_exit "couldn't install chef"
+
+# Create first-boot.json
+cat > "/etc/chef/first-boot.json" << EOF
+{
+ "run_list" :[
+ "role[base]"
+ ]
+}
+EOF
+
+NODE_NAME=node-$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 4 | head -n 1)
+
+# Create client.rb
+cat > '/etc/chef/client.rb' << EOF
+log_location STDOUT
+chef_server_url 'https://aut-chef-server/organizations/my-org'
+validation_client_name 'my-org-validator'
+validation_key '/etc/chef/my_org_validator.pem'
+node_name "${NODE_NAME}"
+EOF
+
+chef-client -j /etc/chef/first-boot.json
+```
+
+It's important that settings in the [client.rb file](/install/config_rb_client/)---for example `chef_server_url` and `http_proxy`---are used to ensure that configuration details are built into the unattended bootstrap process.
+
+##### Setting the initial run-list
+
+{{< readfile file="content/reusable/md/workstation/ctl_chef_client_bootstrap_initial_run_list.md" >}}
diff --git a/content/install/install_chef_air_gap.md b/content/install/install_chef_air_gap.md
new file mode 100644
index 0000000..785eb7c
--- /dev/null
+++ b/content/install/install_chef_air_gap.md
@@ -0,0 +1,497 @@
++++
+title = "Install Chef in an air-gapped environment"
+draft = false
+
+[menu]
+ [menu.install]
+ title = "Air-gapped Installation"
+ identifier = "install/install_chef_air_gap.md Air-gapped Installation"
+ parent = "install"
+ weight = 40
++++
+
+This guide will show you how to run a fully functional Chef environment
+within an [air-gapped](https://en.wikipedia.org/wiki/Air_gap_(networking))
+network.
+
+## Prerequisites
+
+Since a variety of different practices are used to create an air-gapped network, this guide focuses solely on the implementation of Chef software - as such, it makes the following assumptions:
+
+
+- You have a way to get packages to your air-gapped machines
+- Machines on your air-gapped network are able to resolve each other using DNS
+- A server's Fully Qualified Domain Name (FQDN) is the name that will be used by other servers to access it
+- You have a private Ruby gem mirror to supply gems as needed
+- You have an artifact store for file downloads. At a minimum, it should have the following packages available:
+
+ - Chef Workstation
+ - Chef Infra Client
+ - Chef Supermarket
+ - An [install script](#create-an-install-script) for Chef Infra Client
+
+
+### Required cookbooks
+
+This guide will link to the required cookbooks for each piece of software in that software's respective section, but this is a full list of the cookbooks required to complete the entire guide:
+
+For Chef Supermarket:
+
+- [supermarket-omnibus-cookbook](https://supermarket.chef.io/cookbooks/supermarket-omnibus-cookbook)
+- [chef-ingredient](https://supermarket.chef.io/cookbooks/chef-ingredient)
+- [hostsfile](https://supermarket.chef.io/cookbooks/hostsfile)
+
+### Required gems
+
+The following Ruby gems are required to install private Supermarket using the supermarket-omnibus-cookbook:
+
+- mixlib-install
+- mixlib-shellout
+- mixlib-versioning
+- artifactory
+
+These should be accessible from your Gem mirror.
+
+### Create an install script
+
+An install script is used to install Chef Infra Client when bootstrapping a new node. It simply pulls the Chef Infra Client package from your artifact store, and then installs it. For example, on Debian-based Linux systems, it would look similar to this:
+
+```bash
+#!/bin/bash
+
+cd /tmp/
+wget http://packages.example.com/chef_13.2.20-1_amd64.deb
+dpkg -i chef_13.2.20-1_amd64.deb
+```
+
+The install script should be accessible from your artifact store.
+
+## Chef Infra Server
+
+In this section you'll install Chef Infra Server, and create your
+organization and user. Note that to configure Supermarket later
+in this guide, you will need a user that's a member of the `admins`
+group.
+
+1. Download the package from [Chef Downloads](https://www.chef.io/downloads).
+
+1. Upload the package to the machine that will run Chef Infra Server, and then record its location on the file system. The rest of these steps assume this location is in the `/tmp` directory.
+
+1. {{< readfile file="content/reusable/md/server/install_chef_server_install_package.md" >}}
+
+1. Run the following to start all of the services:
+
+ ```bash
+ sudo chef-server-ctl reconfigure
+ ```
+
+ Because Chef Infra Server is composed of many different services
+ that work together to create a functioning system, this step may
+ take a few minutes to complete.
+
+1. {{< readfile file="content/reusable/md/server/ctl_chef_server_user_create_admin.md">}}
+
+1. {{< readfile file="content/reusable/md/server/ctl_chef_server_org_create_summary.md">}}
+
+## Chef Workstation
+
+### Install Chef Workstation
+
+1. First, install the Chef Workstation [installer
+ package](https://www.chef.io/downloads). Use the
+ appropriate tool to run the installer:
+
+ ```bash
+ dpkg -i chef-workstation_0.14.16-1_amd64.deb
+ ```
+
+1. Use the `chef generate repo` command to generate your Chef repo:
+
+ ```bash
+ chef generate repo chef-repo
+ ```
+
+1. Within your Chef repo, create a `.chef` directory:
+
+ ```bash
+ mkdir /chef-repo/.chef
+ ```
+
+1. Copy the `USER.pem` and `ORGANIZATION.pem` files from the server,
+ and move them into the `.chef` directory.
+
+ ```bash
+ scp ssh-user@chef-server.example.com:/path/to/pem/files /chef-repo/.chef/
+ ```
+
+### Create a bootstrap template
+
+By default, `knife bootstrap` uses the `chef-full` template to bootstrap
+a node. This template contains useful features, but it also
+attempts to pull an installation script from `https://omnitruck.chef.io`. In
+this section, you'll copy the contents of the `chef-full` template to a
+custom template, and then modify the package and Ruby gem sources.
+
+1. Navigate to the `.chef` directory, and create a `bootstrap`
+ directory within it:
+
+ ```bash
+ mkdir bootstrap
+ ```
+
+1. Move to the `bootstrap` directory and create a blank template file;
+ this example will use `airgap.erb` for the template name:
+
+ ```bash
+ touch airgap.erb
+ ```
+
+1. Still in the `bootstrap` directory, issue the following command to copy the `chef-full` configuration to your new template:
+
+ ```bash
+ find /opt/chef-workstation/embedded/lib/ruby -type f -name chef-full.erb -exec cat {} \; > airgap.erb
+ ```
+
+ This command searches for the `chef-full` template file under
+ `/opt/chef-workstation/embedded/lib/ruby`, and then outputs the
+ contents of the file to `airgap.erb`. If you used a different
+ template file name, be sure to replace `airgap.erb` with the
+ template file you created during the last step.
+
+1. Update `airgap.erb` to replace `omnitruck.chef.io` with the URL of `install.sh` on your artifact store:
+
+ ```ruby
+ install_sh="<%= knife_config[:bootstrap_url] ? knife_config[:bootstrap_url] : "http://packages.example.com/install.sh" %>"
+ ```
+
+1. Still in your text editor, locate the following line near the bottom
+ of your `airgap.erb` file:
+
+ ```ruby
+ cat > /etc/chef/client.rb <<'EOP'
+ <%= config_content %>
+ EOP
+ ```
+
+ Beneath it, add the following, replacing `gems.example.com` with the
+ URL of your gem mirror:
+
+ ```ruby
+ cat >> /etc/chef/client.rb <<'EOP'
+ rubygems_url "http://gems.example.com"
+ EOP
+ ```
+
+ This appends the appropriate `rubygems_url` setting to the
+ `/etc/chef/client.rb` file that's created during bootstrap, which
+ ensures that your nodes use your internal gem mirror.
+
+### Configure knife
+
+Within the `.chef` directory, create a `config.rb` file and replace
+`USER` and `ORGANIZATION` with the user and organization that you
+created on your Chef Infra Server; replace `chef-server.example.com`
+with your Chef Infra Server URL:
+
+```ruby
+current_dir = File.dirname(__FILE__)
+node_name 'USER'
+client_key "#{current_dir}/USER.pem"
+validation_client_name 'ORGANIZATION-validator'
+validation_key "#{current_dir}/ORGANIZATION.pem"
+chef_server_url 'https://chef-server.example.com/organizations/ORGANIZATION'
+cookbook_path ["#{current_dir}/../cookbooks"]
+knife[:bootstrap_template] = "#{current_dir}/bootstrap/airgap.erb"
+```
+
+The `knife[:bootstrap_template]` option in this example allows you to
+specify the template that `knife bootstrap` will use by default when
+bootstrapping a node. It should point to your custom template within the
+`bootstrap` directory.
+
+Now that `knife` is configured, copy the SSL certificates from your Chef
+Infra Server to your trusted certificates:
+
+```ruby
+knife ssl fetch
+```
+
+## Private Supermarket
+
+Private Supermarket allows you to host your own internal version of the
+[Chef Supermarket](https://supermarket.chef.io) within your air-gapped
+network.
+
+### Requirements
+
+In this section, you will use a wrapper around the
+[supermarket-omnibus-cookbook](https://supermarket.chef.io/cookbooks/supermarket-omnibus-cookbook)
+to install private Supermarket. The Supermarket cookbook depends upon
+the following cookbooks:
+
+- [chef-ingredient](https://supermarket.chef.io/cookbooks/chef-ingredient)
+- [hostsfile](https://supermarket.chef.io/cookbooks/hostsfile)
+
+The following Gems must be accessible using your Gem mirror:
+
+- mixlib-install
+- mixlib-shellout
+- mixlib-versioning
+- artifactory
+
+Your `cookbooks` directory must have all three of these cookbooks
+installed before you will be able to use the Supermarket cookbook
+wrapper. In addition the necessary cookbooks, a private Chef Supermarket
+has the following requirements:
+
+- An operational Chef Infra Server to act as the OAuth 2.0 provider
+- A user account on Chef Infra Server with `admins` privileges
+- A key for the user account on the Chef Infra Server
+- An x86_64 Ubuntu, RHEL, or Amazon Linux host with at least 1 GB memory
+- System clocks synchronized on Chef Infra Server and Supermarket hosts
+- Sufficient disk space to meet project cookbook storage capacity or credentials to store cookbooks in an Amazon Simple Storage Service (S3) bucket
+
+### Configure credentials
+
+First, you'll configure Chef Identity credentials for Supermarket. Chef
+Identity is an OAuth 2.0 service packaged with Chef Infra Server,
+that allows you to use the same credentials to access both server and
+Supermarket.
+
+1. Log on to Chef Infra Server using SSH and elevate to an
+ admin-level user. If running a multi-node Chef Infra Server cluster,
+ log on to the node acting as the primary node in the cluster.
+
+1. Update the `/etc/opscode/chef-server.rb` configuration file.
+
+ {{< readfile file="content/reusable/md/server/config_ocid_application_hash_supermarket.md" >}}
+
+1. Reconfigure Chef Infra Server.
+
+ ```bash
+ sudo chef-server-ctl reconfigure
+ ```
+
+1. Retrieve Supermarket's OAuth 2.0 client credentials:
+
+ Depending on your Chef Infra Server version and configuration (see
+ [chef-server.rb](https://docs.chef.io/server/config_rb_server_optional_settings/#config-rb-server-insecure-addon-compat)),
+ this can be retrieved using [chef-server-ctl oc-id-show-app
+ supermarket](https://docs.chef.io/server/ctl_chef_server/#ctl-chef-server-oc-id-show-app)
+ or is located in `/etc/opscode/oc-id-applications/supermarket.json`:
+
+ ```json
+ {
+ "name": "supermarket",
+ "uid": "0bad0f2eb04e935718e081fb71asdfec3681c81acb9968a8e1e32451d08b",
+ "secret": "17cf1141cc971a10ce307611beda7ffadstr4f1bc98d9f9ca76b9b127879",
+ "redirect_uri": "https://supermarket.mycompany.com/auth/chef_oauth2/callback"
+ }
+ ```
+
+### Create a Wrapper
+
+1. Generate the cookbook:
+
+ ```bash
+ chef generate cookbook my_supermarket_wrapper
+ ```
+
+1. Change directories into that cookbook:
+
+ ```bash
+ cd my_supermarket_wrapper
+ ```
+
+1. Defines the wrapper cookbook's dependency on the
+ `supermarket-omnibus-cookbook` cookbook. Open the `metadata.rb` file
+ of the newly-created cookbook, and then add the following line:
+
+ ```ruby
+ depends 'supermarket-omnibus-cookbook'
+ ```
+
+1. Save and close the `metadata.rb` file.
+
+1. Open the `/recipes/default.rb` recipe located within the
+ newly-generated cookbook and add the following content:
+
+ ```ruby
+ include_recipe 'supermarket-omnibus-cookbook'
+ ```
+
+ This ensures that the `default.rb` file in the
+ `supermarket-omnibus-cookbook` is run.
+
+### Define Attributes
+
+Define the attributes for the Chef Supermarket installation and how it
+connects to Chef Infra Server. One approach would be to hard-code
+attributes in the wrapper cookbook's `default.rb` recipe. A better
+approach is to place these attributes in a [data bag](/policy/data_bags/),
+and then reference them from the recipe. For example, the data bag could
+be named `apps` and then a data bag item within the data bag could be
+named `supermarket`. The following attributes are required:
+
+- `chef_server_url`: the URL of your Chef Infra Server.
+- `chef_oauth2_app_id`: the Chef Identity UID from
+ `/etc/opscode/oc-id-applications/supermarket.json`
+- `chef_oauth2_secret`: The Chef Identity secret from
+ `/etc/opscode/oc-id-applications/supermarket.json`
+- `package_url`: The location of the Supermarket package on your
+ artifact store
+
+To define these attributes, do the following:
+
+1. Open the `recipes/default.rb` file and add the following, **before**
+ the `include_recipe` line that was added in the previous step. This
+ example uses a data bag named `apps` and a data bag item named
+ `supermarket`:
+
+ ```ruby
+ app = data_bag_item('apps', 'supermarket')
+ ```
+
+1. Set the attributes from the data bag:
+
+ ```ruby
+ node.override['supermarket_omnibus']['chef_server_url'] = app['chef_server_url']
+ node.override['supermarket_omnibus']['chef_oauth2_app_id'] = app['chef_oauth2_app_id']
+ node.override['supermarket_omnibus']['chef_oauth2_secret'] = app['chef_oauth2_secret']
+ node.override['supermarket_omnibus']['package_url'] = app['package_url']
+ ```
+
+ Note that the `['package_url']` setting points to the location of
+ the Supermarket package on your artifact store. When finished, the
+ `/recipes/default.rb` file should have code similar to:
+
+ ```ruby
+ app = data_bag_item('apps', 'supermarket')
+
+ node.override['supermarket_omnibus']['chef_server_url'] = app['chef_server_url']
+ node.override['supermarket_omnibus']['chef_oauth2_app_id'] = app['chef_oauth2_app_id']
+ node.override['supermarket_omnibus']['chef_oauth2_secret'] = app['chef_oauth2_secret']
+
+ include_recipe 'supermarket-omnibus-cookbook'
+ ```
+
+ Alternatively, if you chose not to use a data bag to store these
+ values, your `default.rb` should look similar to this:
+
+ ```ruby
+ node.override['supermarket_omnibus']['chef_server_url'] = 'https://chef-server.example.com:443'
+ node.override['supermarket_omnibus']['chef_oauth2_app_id'] = '0bad0f2eb04e935718e081fb71asdfec3681c81acb9968a8e1e32451d08b'
+ node.override['supermarket_omnibus']['chef_oauth2_secret'] = '17cf1141cc971a10ce307611beda7ffadstr4f1bc98d9f9ca76b9b127879'
+ node.override['supermarket_omnibus']['package_url'] = 'http://packages.example.com/supermarket_3.1.22-1_amd64.deb'
+
+ include_recipe 'supermarket-omnibus-cookbook'
+ ```
+
+1. Save and close the `recipes/default.rb` file.
+
+1. Upload all of your cookbooks to Chef Infra Server:
+
+ ```ruby
+ knife cookbook upload -a
+ ```
+
+### Bootstrap Supermarket
+
+Bootstrap the node on which Chef Supermarket is to be installed. For
+example, to bootstrap a node running Ubuntu on Amazon Web Services
+(AWS), the command is similar to:
+
+```bash
+knife bootstrap ip_address -N supermarket-node -x ubuntu --sudo
+```
+
+where:
+
+- `-N` defines the name of the Chef Supermarket node:
+ `supermarket-node`
+- `-x` defines the (ssh) user name: `ubuntu`
+- `--sudo` ensures that sudo is used while running commands on the
+ node during the bootstrap operation
+
+When the bootstrap operation is finished, do the following:
+
+1. Add the wrapper cookbook's `/recipes/default.rb` recipe to the
+ run-list:
+
+ ```bash
+ knife node run_list set supermarket-node recipe[my_supermarket_wrapper::default]
+ ```
+
+ where `supermarket-node` is the name of the node that was just
+ bootstrapped.
+
+1. Start Chef Infra Client on the newly-bootstrapped Chef Supermarket
+ node. For example, using SSH:
+
+ ```bash
+ ssh ubuntu@your-supermarket-node-public-dns
+ ```
+
+1. After accessing the Chef Supermarket node, run Chef Infra Client:
+
+ ```bash
+ sudo chef-client
+ ```
+
+### Connect to Supermarket
+
+To reach the newly spun up private Chef Supermarket, the hostname must
+be resolvable from a workstation. For production use, the hostname
+should have a DNS entry in an appropriate domain that's trusted by each
+user's workstation.
+
+1. Visit the Chef Supermarket hostname in the browser. A private Chef
+ Supermarket will generate and use a self-signed certificate, if a
+ certificate isn't supplied as part of the installation process (using
+ the wrapper cookbook).
+1. If an SSL notice is shown due to your self-signed certificate while
+ connecting to Chef Supermarket using a web browser, accept the SSL
+ certificate. A trusted SSL certificate should be used for private
+ Chef Supermarket that's used in production.
+1. After opening Chef Supermarket in a web browser, click the **Create
+ Account** link. A prompt to log in to Chef Infra Server is
+ shown. Authorize the Chef Supermarket to use the Chef Infra Server
+ account for authentication.
+
+{{< note >}}
+
+The redirect URL specified for Chef Identity **MUST** match the FQDN
+hostname of the Chef Supermarket server. The URI must also be correct:
+`/auth/chef_oauth2/callback`. Otherwise, an error message similar to
+`The redirect uri included isn't valid.` will be shown.
+
+{{< /note >}}
+
+### Configuration updates
+
+#### Knife
+
+Update the `config.rb` file on your workstation to use your private
+Supermarket:
+
+```ruby
+knife[:supermarket_site] = 'https://supermarket.example.com'
+```
+
+#### Berkshelf
+
+If you're using Berkshelf, update your `Berksfile` to replace
+`https://supermarket.chef.io` with the URL of your private Supermarket:
+
+```ruby
+source 'https://supermarket.example.com'
+```
+
+### Upload cookbooks to Supermarket
+
+To upload new cookbooks to your private Supermarket, use the
+`knife supermarket share` command on your workstation:
+
+```ruby
+knife supermarket share chef-ingredient
+```
diff --git a/content/install/installer/_index.md b/content/install/installer/_index.md
index 875038f..4e86797 100644
--- a/content/install/installer/_index.md
+++ b/content/install/installer/_index.md
@@ -31,7 +31,7 @@ This installation process has the following prerequisites:
## Install Chef Infra Client
-To install Chef Infra Client 19, follow these steps:
+To install Chef Infra Client , follow these steps:
1. Download the Chef Infra Client installer.
@@ -44,13 +44,13 @@ To install Chef Infra Client 19, follow these steps:
- Using Wget:
```sh
- wget -O "chef-ice-19.2.rc3-linux.deb" "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/linux/x86_64/chef-ice-19.2.rc3-linux.deb?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=9tqCmX%2F576Nrf6bdiZgK%2FRQP7%2BE%3D&Expires=1780533327"
+ wget -O "chef-ice-19.2.rc3-linux.deb" "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/linux/x86_64/chef-ice-19.2.rc3-linux.deb?AWSAccessKeyId=AKIAW4FPVFT6C42N3U6R&Signature=cmJmplCvrkVXK5MtqCmidrz3rds%3D&Expires=1776916085"
```
- Using curl:
```sh
- curl -o "chef-ice-19.2.rc3-linux.deb" "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/linux/x86_64/chef-ice-19.2.rc3-linux.deb?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=9tqCmX%2F576Nrf6bdiZgK%2FRQP7%2BE%3D&Expires=1780533327"
+ curl -o "chef-ice-19.2.rc3-linux.deb" "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/linux/x86_64/chef-ice-19.2.rc3-linux.deb?AWSAccessKeyId=AKIAW4FPVFT6C42N3U6R&Signature=cmJmplCvrkVXK5MtqCmidrz3rds%3D&Expires=1776916085"
```
{{< /accordion-item >}}
@@ -61,13 +61,13 @@ To install Chef Infra Client 19, follow these steps:
- Using Wget:
```sh
- wget -O chef-ice-19.2.rc3-linux.rpm "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/linux/x86_64/chef-ice-19.2.rc3-linux.rpm?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=gODj1%2BnbpBZ2VYbb3CYjZvU1JXQ%3D&Expires=1780533345"
+ wget -O chef-ice-19.2.rc3-linux.rpm "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/linux/x86_64/chef-ice-19.2.rc3-linux.rpm?AWSAccessKeyId=AKIAW4FPVFT6C42N3U6R&Signature=FUbFKD2qMux2TBK7ltNPLuExQGk%3D&Expires=1776916329"
```
- Using curl:
```sh
- curl -o chef-ice-19.2.rc3-linux.rpm "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/linux/x86_64/chef-ice-19.2.rc3-linux.rpm?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=gODj1%2BnbpBZ2VYbb3CYjZvU1JXQ%3D&Expires=1780533345"
+ curl -o chef-ice-19.2.rc3-linux.rpm "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/linux/x86_64/chef-ice-19.2.rc3-linux.rpm?AWSAccessKeyId=AKIAW4FPVFT6C42N3U6R&Signature=FUbFKD2qMux2TBK7ltNPLuExQGk%3D&Expires=1776916329"
```
{{< /accordion-item >}}
@@ -78,13 +78,13 @@ To install Chef Infra Client 19, follow these steps:
- Using curl:
```sh
- curl -o chef-ice-19.2.rc3-windows.msi "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/windows/x86_64/chef-ice-19.2.rc3-windows.msi?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=ugQFgpkB1TWtaN1mo4iRGGFtgeQ%3D&Expires=1780533357"
+ curl -o chef-ice-19.2.rc3-windows.msi "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/windows/x86_64/chef-ice-19.2.rc3-windows.msi?AWSAccessKeyId=AKIAW4FPVFT6C42N3U6R&Signature=rmb4GgaxE6oPEfVHiAugsg7xMBI%3D&Expires=1776916373"
```
- Using PowerShell:
```ps1
- Invoke-WebRequest -Uri "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/windows/x86_64/chef-ice-19.2.rc3-windows.msi?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=ugQFgpkB1TWtaN1mo4iRGGFtgeQ%3D&Expires=1780533357" -OutFile "chef-ice-19.2.rc3-windows.msi"
+ Invoke-WebRequest -Uri "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/windows/x86_64/chef-ice-19.2.rc3-windows.msi?AWSAccessKeyId=AKIAW4FPVFT6C42N3U6R&Signature=rmb4GgaxE6oPEfVHiAugsg7xMBI%3D&Expires=1776916373" -OutFile "chef-ice-19.2.rc3-windows.msi"
```
{{< /accordion-item >}}
diff --git a/content/install/migration_tool/_index.md b/content/install/migration_tool/_index.md
index f668e45..ae3462f 100644
--- a/content/install/migration_tool/_index.md
+++ b/content/install/migration_tool/_index.md
@@ -8,14 +8,14 @@ parent = "install/migration_tool"
weight = 10
+++
-The Chef Infra Client migration tool (`chef-migrate`) allows you to install or upgrade Chef Infra Client to the latest version in both online and air-gapped environments.
+The Chef Infra Client migration tool (`migrate-ice`) allows you to install or upgrade Chef Infra Client to the latest version in both online and air-gapped environments.
## Key functions
-- **Fresh installation:** Install Chef Infra Client 19 RC3
-- **Side-by-side installation:** Install Chef Infra Client 19 RC3 and remove or keep the previous Infra Client version. If you keep the previous version in side-by-side mode, the path to the most recent version takes precedence
+- **Fresh installation:** Install Chef Infra Client
+- **Side-by-side installation:** Install Chef Infra Client and remove or keep the previous Infra Client version. If you keep the previous version in side-by-side mode, the path to the most recent version takes precedence
- **Omnibus upgrade:** Upgrade from Omnibus-based Chef Infra Client 17.x or 18.x versions
-- **Habitat upgrade:** Upgrade Habitat-packaged Chef Infra Client 19 RC releases
+- **Habitat upgrade:** Upgrade Habitat-packaged Chef Infra Client releases
## Supported platforms
@@ -29,4 +29,4 @@ To install or upgrade Chef Infra Client, see these guides:
- [Install](install)
- [Online upgrade](upgrade_online)
- [Air-gapped upgrade](upgrade_airgap)
-- [`chef-migrate` CLI reference](reference)
+- [`migrate-ice` CLI reference](reference)
diff --git a/content/install/migration_tool/install.md b/content/install/migration_tool/install.md
index d6062f4..4a6fed6 100644
--- a/content/install/migration_tool/install.md
+++ b/content/install/migration_tool/install.md
@@ -12,7 +12,7 @@ This page documents how to install Chef Infra Client RC3 in an online environmen
## Supported platforms
-Chef Infra Client 19 RC3 is supported on:
+Chef Infra Client is supported on:
- Linux x86-64
- Windows x86-64
@@ -31,46 +31,96 @@ To install Chef Infra Client on Linux, follow these steps:
chef-client --version
```
-1. Download the Chef Infra Client migration tool.
+1. Get the latest version number of the Infra Client migration tool (migrate-ice).
- The migration tool is available for download as a zipped tar file using a pre-signed URL from an S3 bucket until April 23, 2026.
+ ```sh
+ curl "https://commercial-acceptance.downloads.chef.co/stable/migrate-ice/versions/latest?license_id="
+ ```
+
+ Replace `` with your Progress Chef License ID.
+
+ The response returns the latest version.
+
+1. Download the Chef Infra Client migration tool using curl or Wget.
+
+ {{< accordion-list id="download-migration-tool-curl-wget-linux" data-allow-all-closed="true" >}}
- Using curl:
+ {{< accordion-item accordion-title-link="download-migration-tool-with-curl-linux" accordion-title="Download migration tool with curl" >}}
+
+ Download the migration tool using curl:
```sh
- curl -o migration-tools-1.1.rc3-linux.tar.gz "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/migrate-ice/1.1.RC3/linux/migration-tools-1.1.rc3-linux.tar.gz?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=O8rQUc0jy%2BeP7U1WspJasr7qMTY%3D&Expires=1780533385"
+ curl -o migration-tools--linux.tar.gz "https://commercial-acceptance.downloads.chef.co/current/migrate-ice/packages?v=&license_id="
```
- Using Wget:
+ Replace:
+
+ - `` with the version number from the previous step
+ - `` with your Progress Chef License ID
+
+ {{< /accordion-item >}}
+
+ {{< accordion-item accordion-title-link="download-migration-tool-with-wget-linux" accordion-title="Download migration tool with Wget" >}}
+
+ Download the migration tool using Wget:
```sh
- wget -O "migration-tools-1.1.rc3-linux.tar.gz" "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/migrate-ice/1.1.RC3/linux/migration-tools-1.1.rc3-linux.tar.gz?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=O8rQUc0jy%2BeP7U1WspJasr7qMTY%3D&Expires=1780533385"
+ wget -O "migration-tools--linux.tar.gz" "https://commercial-acceptance.downloads.chef.co/current/migrate-ice/packages?v=&license_id="
```
+ Replace:
+
+ - `` with the version number from the previous step
+ - `` with your Progress Chef License ID
+
+ {{< /accordion-item >}}
+
+ {{< /accordion-list >}}
+
1. Extract the migration tool and make it executable.
```sh
- tar -xvf migration-tools-1.1.rc3-linux.tar.gz -C /path/to/temp/folder
+ tar -xvf migration-tools--linux.tar.gz -C /path/to/temp/folder
cd /path/to/temp/folder
- chmod +x chef-migrate
- mv chef-migrate /usr/local/bin/
+ chmod +x migrate-ice
+ mv migrate-ice /usr/local/bin/
```
1. Optional: Verify that the migration tool is installed.
```sh
- chef-migrate --help
+ migrate-ice --help
```
The migration tool returns available commands and usage guidelines.
-1. Install Chef Infra Client using [`chef-migrate apply`](reference):
+1. Install Chef Infra Client using [`migrate-ice apply`](reference):
+
+ You can install Chef Infra Client using specifying a download URL or an Infra Client version number.
+
+ {{< accordion-list id="migrate-ice-download-linux" data-allow-all-closed="true" >}}
+ {{< accordion-item accordion-title-link="migrate-ice-download-url-linux" accordion-title="Specify download URL" >}}
+
+ ```sh
+ sudo migrate-ice apply online --fresh-install --download-url ""
+ ```
+
+ Replace `` with the Chef Infra Client package download URL.
+
+ {{< /accordion-item >}}
+ {{< accordion-item accordion-title-link="migrate-ice-download-version-number-linux" accordion-title="Specify version number" >}}
```sh
- sudo chef-migrate apply online --fresh-install --download-url "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/linux/x86_64/chef-ice-19.2.rc3-linux.tar.gz?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=htVtnPFhoan9wyXixccqDFp0jmU%3D&Expires=1780533226" --license-key ""
+ sudo migrate-ice apply online --fresh-install --chef-version --license-key ""
```
- Replace `` with your Progress Chef License key.
+ Replace:
+
+ - `` with the Chef Infra Client version number (for example, `19.1.150`)
+ - `` with your Progress Chef License key
+
+ {{< /accordion-item >}}
+ {{< /accordion-list >}}
1. Verify the Chef Infra Client installation.
@@ -88,46 +138,96 @@ To install Chef Infra Client on Windows, follow these steps:
chef-client --version
```
-1. Download the Chef Infra Client migration tool.
+1. Get the latest version number of the Infra Client migration tool (migrate-ice):
- The migration tool is available for download as a ZIP file using a pre-signed address from an S3 bucket until April 23, 2026.
+ ```powershell
+ curl "https://commercial-acceptance.downloads.chef.co/stable/migrate-ice/versions/latest?license_id="
+ ```
+
+ Replace `` with your Progress Chef License ID.
+
+ The response returns the latest version.
+
+1. Download the migration tool using curl or PowerShell:
+
+ {{< accordion-list id="download-migration-tool-curl-powershell-windows" data-allow-all-closed="true" >}}
- Using curl:
+ {{< accordion-item accordion-title-link="download-migration-tool-with-curl-windows" accordion-title="Download migration tool with curl" >}}
+
+ Download the migration tool using curl:
```powershell
- curl -o migration-tools-1.1.rc3-windows.zip "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/migrate-ice/1.1.RC3/windows/migration-tools-1.1.rc3-windows.zip?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=xyfZ7g7D5jLF5jY%2B8DfBkEedSUA%3D&Expires=1780533399"
+ curl -o migration-tools--windows.zip "https://commercial-acceptance.downloads.chef.co/current/migrate-ice/packages?v=&license_id="
```
- Using PowerShell:
+ Replace:
+
+ - `` with the version number from the previous step
+ - `` with your Progress Chef License ID
+
+ {{< /accordion-item >}}
+
+ {{< accordion-item accordion-title-link="download-migration-tool-with-powershell-windows" accordion-title="Download migration tool with PowerShell" >}}
+
+ Download the migration tool using PowerShell:
```powershell
- Invoke-WebRequest -Uri "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/migrate-ice/1.1.RC3/windows/migration-tools-1.1.rc3-windows.zip?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=xyfZ7g7D5jLF5jY%2B8DfBkEedSUA%3D&Expires=1780533399" -OutFile "migration-tools-1.1.rc3-windows.zip"
+ Invoke-WebRequest -Uri "https://commercial-acceptance.downloads.chef.co/current/migrate-ice/packages?v=&license_id=" -OutFile "migration-tools--windows.zip"
```
+ Replace:
+
+ - `` with the version number from the previous step
+ - `` with your Progress Chef License ID
+
+ {{< /accordion-item >}}
+
+ {{< /accordion-list >}}
+
1. Extract the migration tool.
```powershell
mkdir C:\migrate-tool
- move "migration-tools-1.1.rc3-windows.zip" "C:\migrate-tool\"
+ move "migration-tools--windows.zip" "C:\migrate-tool\"
cd C:\migrate-tool
- Expand-Archive -Path "migration-tools-1.1.rc3-windows.zip" -DestinationPath "."
+ Expand-Archive -Path "migration-tools--windows.zip" -DestinationPath "."
```
1. Optional: Verify that the migration tool works.
```powershell
- .\chef-migrate --help
+ .\migrate-ice --help
```
The migration tool returns available commands and usage guidelines.
-1. Install Chef Infra Client using [`chef-migrate apply`](reference):
+1. Install Chef Infra Client using [`migrate-ice apply`](reference):
+
+ You can install Chef Infra Client using specifying a download URL or an Infra Client version number.
+
+ {{< accordion-list id="migrate-ice-download-windows" data-allow-all-closed="true" >}}
+ {{< accordion-item accordion-title-link="migrate-ice-download-url-windows" accordion-title="Specify download URL" >}}
+
+ ```powershell
+ .\migrate-ice apply online --fresh-install --download-url ""
+ ```
+
+ Replace `` with the Chef Infra Client package download URL.
+
+ {{< /accordion-item >}}
+ {{< accordion-item accordion-title-link="migrate-ice-download-version-number-windows" accordion-title="Specify version number" >}}
```powershell
- .\chef-migrate apply online --fresh-install --download-url "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/windows/x86_64/chef-ice-19.2.rc3-windows.tar.gz?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=2jIjDACxF0EYf8yICEp698kt0xY%3D&Expires=1780533373" --license-key ""
+ .\migrate-ice apply online --fresh-install --chef-version --license-key ""
```
- Replace `` with your Progress Chef License key.
+ Replace:
+
+ - `` with the Chef Infra Client version number (for example, `19.1.150`)
+ - `` with your Progress Chef License key
+
+ {{< /accordion-item >}}
+ {{< /accordion-list >}}
1. Verify the Chef Infra Client installation.
diff --git a/content/install/migration_tool/install_airgap.md b/content/install/migration_tool/install_airgap.md
index 1937c0c..17f2745 100644
--- a/content/install/migration_tool/install_airgap.md
+++ b/content/install/migration_tool/install_airgap.md
@@ -13,7 +13,7 @@ This page documents how to do a fresh install of Chef Infra Client RC3 in an air
## Supported platforms
-Chef Infra Client 19 RC3 is supported on Linux x86-64 systems.
+Chef Infra Client is supported on Linux x86-64 systems.
## Prerequisites
@@ -23,61 +23,126 @@ Chef Infra Client 19 RC3 is supported on Linux x86-64 systems.
To install Chef Infra Client, follow these steps:
-1. On an internet-connected machine, download the Chef Infra Client 19 RC3 tar file.
+1. On an internet-connected machine, get the Chef Infra Client tar package download URL:
- Chef Infra Client is available in a zipped tar file using a pre-signed URL from an S3 bucket until April 23, 2026.
+ ```sh
+ curl "https://commercial-acceptance.downloads.chef.co/current/chef-ice/packages?v=&license_id="
+ ```
+
+ Replace:
+
+ - `` with the Chef Infra Client version number (for example, 19.1.152)
+ - `` with your Progress Chef License ID
+
+ The response returns download URLs for different platforms and package types. Use the URL from the `linux..tar.url` field in the JSON response (for example, `linux.x86_64.tar.url` if the architecture is x86-64).
+
+1. Download the Chef Infra Client package using curl or Wget:
+
+ {{< accordion-list id="download-chef-infra-client-curl-wget" data-allow-all-closed="true" >}}
+
+ {{< accordion-item accordion-title="Download Infra Client with curl" accordion-title-link="download-chef-infra-client-curl" >}}
- Download using curl:
+ Download the tar file using curl:
```sh
- curl -o chef-ice-19.2.rc3-linux.tar.gz "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/linux/x86_64/chef-ice-19.2.rc3-linux.tar.gz?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=htVtnPFhoan9wyXixccqDFp0jmU%3D&Expires=1780533226"
+ curl -o chef-ice--linux.tar.gz ""
```
+ Replace:
+
+ - `` with the URL from the `linux..tar.url` field
+ - `` with the Chef Infra Client version number
+
+ {{< /accordion-item >}}
+
+ {{< accordion-item accordion-title="Download Infra Client with Wget" accordion-title-link="download-chef-infra-client-wget" >}}
+
Download using Wget:
```sh
- wget -O "chef-ice-19.2.rc3-linux.tar.gz" "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/linux/x86_64/chef-ice-19.2.rc3-linux.tar.gz?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=htVtnPFhoan9wyXixccqDFp0jmU%3D&Expires=1780533226"
+ wget -O "chef-ice--linux.tar.gz" ""
+ ```
+
+ Replace:
+
+ - `` with the URL from the `linux..tar.url` field
+ - `` with the Chef Infra Client version number
+
+ {{< /accordion-item >}}
+
+ {{< /accordion-list >}}
+
+1. On an internet-connected machine, get the latest version of the Chef Infra Client migration tool (migrate-ice).
+
+ ```sh
+ curl "https://commercial-acceptance.downloads.chef.co/stable/migrate-ice/versions/latest?license_id="
```
-1. On an internet-connected machine, download the Chef Infra Client migration tool.
+ Replace `` with your Progress Chef License ID.
- The migration tool is available for download as a zipped tar file using a pre-signed URL from an S3 bucket until April 23, 2026.
+ The response returns the latest version number.
+
+1. Download the migration tool:
+
+ {{< accordion-list id="my-accordion" data-allow-all-closed="true" >}}
+
+ {{< accordion-item accordion-title="Download migration tool with curl" accordion-title-link="download-migration-tool-curl" >}}
Using curl:
```sh
- curl -o migration-tools-1.1.rc3-linux.tar.gz "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/migrate-ice/1.1.RC3/linux/migration-tools-1.1.rc3-linux.tar.gz?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=O8rQUc0jy%2BeP7U1WspJasr7qMTY%3D&Expires=1780533385"
+ curl -o migration-tools--linux.tar.gz "https://commercial-acceptance.downloads.chef.co/current/migrate-ice/packages?v=&license_id="
```
+ Replace:
+
+ - `` with the version number from the previous step
+ - `` with your Progress Chef License ID
+
+ {{< /accordion-item >}}
+
+ {{< accordion-item accordion-title="Download migration tool with Wget" accordion-title-link="download-migration-tool-wget" >}}
+
Using Wget:
```sh
- wget -O "migration-tools-1.1.rc3-linux.tar.gz" "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/migrate-ice/1.1.RC3/linux/migration-tools-1.1.rc3-linux.tar.gz?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=O8rQUc0jy%2BeP7U1WspJasr7qMTY%3D&Expires=1780533385"
+ wget -O "migration-tools--linux.tar.gz" "https://commercial-acceptance.downloads.chef.co/current/migrate-ice/packages?v=&license_id="
```
+ Replace:
+
+ - `` with the version number from the previous step
+ - `` with your Progress Chef License ID
+
+ {{< /accordion-item >}}
+
+ {{< /accordion-list >}}
+
1. Extract the migration tool and make it executable.
```sh
- tar -xvf migration-tools-1.1.rc3-linux.tar.gz -C /path/to/temp/folder
+ tar -xvf migration-tools--linux.tar.gz -C /path/to/temp/folder
cd /path/to/temp/folder
- chmod +x chef-migrate
- mv chef-migrate /usr/local/bin/
+ chmod +x migrate-ice
+ mv migrate-ice /usr/local/bin/
```
1. Optional: Verify that the migration tool is installed.
```sh
- chef-migrate --help
+ migrate-ice --help
```
The migration tool returns available commands and usage guidelines.
-1. Install Chef Infra CLient using [`chef-migrate apply`](reference):
+1. Install Chef Infra CLient using [`migrate-ice apply`](reference):
```sh
- sudo chef-migrate apply airgap --fresh-install --license-key ""
+ sudo migrate-ice apply airgap --fresh-install
```
+ Replace `` with the path to the Chef Infra Client tar file.
+
1. Verify that Chef Infra Client is installed.
```sh
diff --git a/content/install/migration_tool/reference.md b/content/install/migration_tool/reference.md
index 23830cb..4810d73 100644
--- a/content/install/migration_tool/reference.md
+++ b/content/install/migration_tool/reference.md
@@ -10,18 +10,18 @@ weight = 999
## Syntax
-The `chef-migrate apply` command upgrades or installs Chef Infra Client to version 19.
+The `migrate-ice apply` command upgrades or installs Chef Infra Client to version 19.
This command has the following basic syntax:
```sh
-chef-migrate apply {airgap|online} [flags]
+migrate-ice apply {airgap|online} [flags]
```
It supports two subcommands:
-- `airgap`: Uses pre-downloaded air-gapped bundles to install or upgrade Chef Infra Client 19.
-- `online`: Uses network-connected resources to download and install Chef Infra Client 19.
+- `airgap`: Uses pre-downloaded air-gapped bundles to install or upgrade Chef Infra Client .
+- `online`: Uses network-connected resources to download and install Chef Infra Client .
## Flags
@@ -30,6 +30,20 @@ It supports two subcommands:
`--debug`
: Enable debug logs. Logs are available in `/var/log/chef19migrate.log`. Valid values are: `true` or `false`.
+`--chef-version `
+: Specify the Chef Infra Client version to download and install. Only applicable for online mode. The `--license-key` option is required with `--chef-version`.
+
+ The tool performs the following actions:
+
+ - **Download**: Automatically downloads the specified Chef Infra Client package from the official repository
+ - **Validation**: Checks version format and ensures it's a supported Chef 19.x.x version
+ - **Package Path**: The downloaded package is stored at a predefined location for later use
+ - **Skip Option**: If `--chef-version` isn't provided, the flag is skipped (useful when using `--download-url` instead)
+
+ Valid format: `19.x.x` (for example, `19.1.0`, `19.0.5`)
+
+ This flag is mutually exclusive with `--download-url`. Use one or the other, not both.
+
`--download-url `
: Specify the Chef Infra Client download location.
@@ -108,19 +122,35 @@ It supports two subcommands:
### Install Chef Infra Client
-These examples show how to perform a fresh install of Chef Infra Client 19 RC3.
+These examples show how to perform a fresh install of Chef Infra Client .
-Standard online installation:
+Install Chef Infra Client by specifying a download URL:
```sh
-chef-migrate apply online --fresh-install --download-url "" --license-key ""
+migrate-ice apply online --fresh-install --download-url "" --license-key ""
```
+Replace:
+
+- `` with the Chef Infra Client package download URL
+- `` with a valid Progress Chef License key
+
+Install Chef Infra Client in an online environment by specifying a version number:
+
+```sh
+migrate-ice apply online --fresh-install --chef-version --license-key ""
+```
+
+Replace:
+
+- `` with a valid Progress Chef License key
+- `` the full three-part Chef Infra Client version number (for example, `19.1.0`)
+
@@ -131,13 +161,13 @@ These examples show how to upgrade Chef Infra Client to version 19 RC3 from an e
Standard online upgrade:
```sh
-chef-migrate apply online --download-url "" --license-key ""
+migrate-ice apply online --download-url "" --license-key ""
```
Standard air-gapped upgrade:
```sh
-chef-migrate apply airgap --license-key ""
+migrate-ice apply airgap --license-key ""
```
### Manage Omnibus-based Chef Infra Client
@@ -145,31 +175,31 @@ chef-migrate apply airgap --license-key ""
Preserve an Omnibus-based Chef Infra Client installation:
```sh
-chef-migrate apply {airgap|online} --license-key "" --preserve-omnibus
+migrate-ice apply {airgap|online} --license-key "" --preserve-omnibus
```
Log a warning if the `client.rb` config file references the Omnibus-based Chef Infra Client installation (`/opt/chef`):
```sh
-chef-migrate apply {airgap|online} --license-key "" --process-config warn
+migrate-ice apply {airgap|online} --license-key "" --process-config warn
```
Replace the existing Omnibus-based Chef binaries (for example, `ruby`, `chef-client`, and `openssl`) with symbolic links pointing to their Habitat-based equivalents.
```sh
-chef-migrate apply {airgap|online} --license-key "" --preserve-omnibus --symlink
+migrate-ice apply {airgap|online} --license-key "" --preserve-omnibus --symlink
```
Remount Chef Infra Client from `/opt/chef` to `/hab`:
```sh
-chef-migrate apply {airgap|online} --license-key "" --fstab apply
+migrate-ice apply {airgap|online} --license-key "" --fstab apply
```
Abort the migration process if `/opt/chef` is already mounted:
```sh
-chef-migrate apply {airgap|online} --license-key "" --fstab fail
+migrate-ice apply {airgap|online} --license-key "" --fstab fail
```
### Manage Chef Habitat
@@ -177,7 +207,7 @@ chef-migrate apply {airgap|online} --license-key "" --fstab fail
Upgrade Chef Habitat while installing Chef Infra Client:
```sh
-chef-migrate apply {airgap|online} --license-key "" --habitat-upgrade
+migrate-ice apply {airgap|online} --license-key "" --habitat-upgrade
```
### SELinux profiles
@@ -185,11 +215,11 @@ chef-migrate apply {airgap|online} --license-key "" --habitat-upgra
Install the default SELinux profile:
```sh
-chef-migrate apply {airgap|online} --license-key "" --selinux-profile default --selinux-ignore-warnings
+migrate-ice apply {airgap|online} --license-key "" --selinux-profile default --selinux-ignore-warnings
```
Install a custom SELinux profile:
```sh
-chef-migrate apply {airgap|online} --license-key "" --selinux-profile
+migrate-ice apply {airgap|online} --license-key "" --selinux-profile
```
diff --git a/content/install/migration_tool/upgrade_airgap.md b/content/install/migration_tool/upgrade_airgap.md
index 43f6969..154d0c5 100644
--- a/content/install/migration_tool/upgrade_airgap.md
+++ b/content/install/migration_tool/upgrade_airgap.md
@@ -12,7 +12,7 @@ This page documents how to upgrade Chef Infra Client to version 19 RC3 in an air
## Supported platforms
-Chef Infra Client 19 RC3 is supported on:
+Chef Infra Client is supported on:
- Linux x86-64
- Windows x86-64
@@ -21,69 +21,125 @@ Chef Infra Client 19 RC3 is supported on:
- a valid Chef License key
-## Upgrade to Chef Infra Client 19 RC3 on Linux
+## Upgrade to Chef Infra Client on Linux
To upgrade Chef Infra Client, follow these steps:
-1. On an internet-connected machine, download the Chef Infra Client 19 RC3 tar file.
+1. On an internet-connected machine, get the download URL for the Chef Infra Client tar package:
- Chef Infra Client is available in a zipped tar file using a pre-signed URL from an S3 bucket until April 23, 2026.
+ ```sh
+ curl "https://commercial-acceptance.downloads.chef.co/current/chef-ice/packages?v=&license_id="
+ ```
+
+ Replace `` with the Chef Infra Client version number (for example, 19.1.152) and `` with your Progress Chef License ID.
+
+ The response returns download URLs for different platforms and package types. Use the URL from the `linux..tar.url` field in the JSON response (for example, `linux.x86_64.tar.url` if the architecture is x86_64).
+
+1. Download the Chef Infra Client tar file.
- Download using curl:
+ {{< accordion-list id="download-chef-infra-client-curl-wget-linux" data-allow-all-closed="true" >}}
+
+ {{< accordion-item accordion-title="Download using curl" accordion-title-link="download-chef-infra-client-curl-linux" >}}
+
+ Download the tar file using curl:
```sh
- curl -o chef-ice-19.2.rc3-linux.tar.gz "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/linux/x86_64/chef-ice-19.2.rc3-linux.tar.gz?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=htVtnPFhoan9wyXixccqDFp0jmU%3D&Expires=1780533226"
+ curl -o chef-ice--linux.tar.gz ""
```
+ Replace:
+
+ - `` with the URL from the `linux..tar.url` field
+ - `` with the Chef Infra Client version number
+
+ {{< /accordion-item >}}
+
+ {{< accordion-item accordion-title="Download using Wget" accordion-title-link="download-chef-infra-client-wget-linux" >}}
+
Download using Wget:
```sh
- wget -O "chef-ice-19.2.rc3-linux.tar.gz" "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/linux/x86_64/chef-ice-19.2.rc3-linux.tar.gz?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=htVtnPFhoan9wyXixccqDFp0jmU%3D&Expires=1780533226"
+ wget -O "chef-ice--linux.tar.gz" ""
```
-1. On an internet-connected machine, download the Chef Infra Client migration tool.
+ Replace:
+
+ - `` with the URL from the `linux..tar.url` field
+ - `` with the Chef Infra Client version number
- The migration tool is available for download as a zipped tar file using a pre-signed URL from an S3 bucket until April 23, 2026.
+ {{< /accordion-item >}}
- Using curl:
+ {{< /accordion-list >}}
+
+1. On an internet-connected machine, get the latest version of the Chef Infra Client migration tool (migrate-ice).
+
+ ```sh
+ curl "https://commercial-acceptance.downloads.chef.co/stable/migrate-ice/versions/latest?license_id="
+ ```
+
+ Replace `` with your Progress Chef License ID.
+
+ The response returns the latest version number.
+
+1. Download the Chef Infra Client migration tool package.
+
+ {{< accordion-list id="download-migration-tool-package-curl-wget-linux" data-allow-all-closed="true" >}}
+
+ {{< accordion-item accordion-title="Download migration tool with curl" accordion-title-link="download-migration-tool-curl-linux" >}}
+
+ Download migration tool using curl:
```sh
- curl -o migration-tools-1.1.rc3-linux.tar.gz "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/migrate-ice/1.1.RC3/linux/migration-tools-1.1.rc3-linux.tar.gz?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=O8rQUc0jy%2BeP7U1WspJasr7qMTY%3D&Expires=1780533385"
+ curl -o migration-tools--linux.tar.gz "https://commercial-acceptance.downloads.chef.co/current/migrate-ice/packages?v=&license_id="
```
- Using Wget:
+ Replace:
+
+ - `` with the version number from the previous step
+ - `` with your Progress Chef License ID
+
+ {{< /accordion-item >}}
+
+ {{< accordion-item accordion-title="Download migration tool with Wget" accordion-title-link="download-migration-tool-wget-linux" >}}
+
+ Download migration tool using Wget:
```sh
- wget -O "migration-tools-1.1.rc3-linux.tar.gz" "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/migrate-ice/1.1.RC3/linux/migration-tools-1.1.rc3-linux.tar.gz?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=O8rQUc0jy%2BeP7U1WspJasr7qMTY%3D&Expires=1780533385"
+ wget -O "migration-tools--linux.tar.gz" "https://commercial-acceptance.downloads.chef.co/current/migrate-ice/packages?v=&license_id="
```
+ Replace:
+ - `` with the version number from the previous step
+ - `` with your Progress Chef License ID
+
+ {{< /accordion-item >}}
+
+ {{< /accordion-list >}}
+
1. Extract the migration tool and make it executable.
```sh
- tar -xvf migration-tools-1.1.rc3-linux.tar.gz -C /path/to/temp/folder
+ tar -xvf migration-tools--linux.tar.gz -C /path/to/temp/folder
cd /path/to/temp/folder
- chmod +x chef-migrate
- mv chef-migrate /usr/local/bin/
+ chmod +x migrate-ice
+ mv migrate-ice /usr/local/bin/
```
1. Optional: Verify that the migration tool is installed.
```sh
- chef-migrate --help
+ migrate-ice --help
```
The migration tool returns available commands and usage guidelines.
-1. Install Chef Infra Client by specifying the path to the tar file using [`chef-migrate apply`](reference).
+1. Install Chef Infra Client by specifying the path to the tar file using [`migrate-ice apply`](reference).
```sh
- sudo chef-migrate apply airgap --license-key ""
+ sudo migrate-ice apply airgap
```
- Replace:
-
- - `` with the path to the Chef Infra Client tar file.
- - `` with your Progress Chef License key.
+ Replace `` with the path to the Chef Infra Client tar file.
1. Verify that Chef Infra Client is installed.
@@ -91,67 +147,122 @@ To upgrade Chef Infra Client, follow these steps:
chef-client --version
```
-## Upgrade to Chef Infra Client 19 RC3 on Windows
+## Upgrade to Chef Infra Client on Windows
To upgrade Chef Infra Client, follow these steps:
-1. On an internet-connected machine, download the Chef Infra Client 19 RC3 tar file.
+1. On an internet-connected machine, get the download URL for the Chef Infra Client tar package:
+
+ ```powershell
+ curl "https://commercial-acceptance.downloads.chef.co/current/chef-ice/packages?v=&license_id="
+ ```
+
+ Replace `` with the Chef Infra Client version number (for example, 19.1.152) and `` with your Progress Chef License ID.
+
+ The response returns download URLs for different platforms and package types. Use the URL from the `windows..tar.url` field in the JSON response (for example, `windows.x86_64.tar.url` if the architecture is x86_64).
+
+1. Download the Chef Infra Client tar file.
+
+ {{< accordion-list id="my-accordion" data-allow-all-closed="true" >}}
- Chef Infra Client is available in a tar file using a pre-signed address from an S3 bucket until April 23, 2026.
+ {{< accordion-item accordion-title="Download Chef Infra Client with curl" accordion-title-link="download-chef-infra-client-curl-windows" >}}
- Download using curl:
+ Download the tar file using curl:
```powershell
- curl -o chef-ice-19.2.rc3-windows.tar.gz "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/windows/x86_64/chef-ice-19.2.rc3-windows.tar.gz?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=2jIjDACxF0EYf8yICEp698kt0xY%3D&Expires=1780533373"
+ curl -o chef-ice--windows.tar.gz ""
```
+ {{< /accordion-item >}}
+
+ {{< accordion-item accordion-title="Download Chef Infra Client with PowerShell" accordion-title-link="download-chef-infra-client-powershell-windows" >}}
+
Download using PowerShell:
```powershell
- Invoke-WebRequest -Uri "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/chef-ice/19.2.RC3/windows/x86_64/chef-ice-19.2.rc3-windows.tar.gz?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=2jIjDACxF0EYf8yICEp698kt0xY%3D&Expires=1780533373" -OutFile "chef-ice-19.2.rc3-windows.tar.gz"
+ Invoke-WebRequest -Uri "" -OutFile "chef-ice--windows.tar.gz"
```
-1. On an internet-connected machine, download the Chef Infra Client migration tool.
+ Replace:
+
+ - `` with the URL from the `windows..tar.url` field
+ - `` with the Chef Infra Client version number
- The migration tool is available for download as a ZIP file using a pre-signed address from an S3 bucket until April 23, 2026.
+ {{< /accordion-item >}}
+
+ {{< /accordion-list >}}
+
+1. On an internet-connected machine, get the latest version of the Chef Infra Client migration tool (migrate-ice).
+
+ ```powershell
+ curl "https://commercial-acceptance.downloads.chef.co/stable/migrate-ice/versions/latest?license_id="
+ ```
+
+ Replace `` with your Progress Chef License ID.
+
+ The response returns the latest version number. Use this version to download the migration tool package.
+
+1. Download the Chef Infra Client migration tool package.
+
+ {{< accordion-list id="download-migration-tool-curl-powershell-windows" data-allow-all-closed="true" >}}
+
+ {{< accordion-item accordion-title="Download migration tool with curl" accordion-title-link="download-migration-tool-curl-windows" >}}
Using curl:
```powershell
- curl -o migration-tools-1.1.rc3-windows.zip "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/migrate-ice/1.1.RC3/windows/migration-tools-1.1.rc3-windows.zip?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=xyfZ7g7D5jLF5jY%2B8DfBkEedSUA%3D&Expires=1780533399"
+ curl -o migration-tools--windows.zip "https://commercial-acceptance.downloads.chef.co/current/migrate-ice/packages?v=&license_id="
```
+ Replace:
+
+ - `` with the version number from the previous step
+ - `` with your Progress Chef License ID
+
+ {{< /accordion-item >}}
+
+ {{< accordion-item accordion-title="Download migration tool with PowerShell" accordion-title-link="download-migration-tool-powershell-windows" >}}
+
Using PowerShell:
```powershell
- Invoke-WebRequest -Uri "https://chef-hab-migration-tool-bucket.s3.amazonaws.com/Release-Candidate-3/migrate-ice/1.1.RC3/windows/migration-tools-1.1.rc3-windows.zip?AWSAccessKeyId=AKIAW4FPVFT6PA6EXTHQ&Signature=xyfZ7g7D5jLF5jY%2B8DfBkEedSUA%3D&Expires=1780533399" -OutFile "migration-tools-1.1.rc3-windows.zip"
+ Invoke-WebRequest -Uri "https://commercial-acceptance.downloads.chef.co/current/migrate-ice/packages?v=&license_id=" -OutFile "migration-tools--windows.zip"
```
+ Replace:
+
+ - `` with the version number from the previous step
+ - `` with your Progress Chef License ID
+
+ {{< /accordion-item >}}
+
+ {{< /accordion-list >}}
+
1. Extract the migration tool.
```powershell
mkdir C:\migrate-tool
- move "migration-tools-1.1.rc3-windows.zip" "C:\migrate-tool\"
- move "chef-ice-19.2.rc3-windows.tar.gz" "C:\migrate-tool\"
+ move "migration-tools--windows.zip" "C:\migrate-tool\"
+ move "chef-ice--windows.tar.gz" "C:\migrate-tool\"
cd C:\migrate-tool
- Expand-Archive -Path "migration-tools-1.1.rc3-windows.zip" -DestinationPath "."
+ Expand-Archive -Path "migration-tools--windows.zip" -DestinationPath "."
```
1. Optional: Verify that the migration tool works.
```powershell
- .\chef-migrate --help
+ .\migrate-ice --help
```
The migration tool returns available commands and usage guidelines.
-1. Upgrade Chef Infra Client by specifying the path to the tar file using [`chef-migrate apply`](reference).
+1. Upgrade Chef Infra Client by specifying the path to the tar file using [`migrate-ice apply`](reference).
```powershell
- .\chef-migrate apply airgap "C:\migrate-tool\chef-ice-19.2.rc3-windows.tar.gz" --license-key ""
+ .\migrate-ice apply airgap "C:\migrate-tool\chef-ice--windows.tar.gz"
```
- Replace `