mirror of
https://github.com/inspec/inspec
synced 2024-11-22 20:53:11 +00:00
* ENHANCE: Extend lxc resource to test the properties Signed-off-by: Sonu Saha <sonu.saha@progress.com> * TEST: Extend test for introduced properties Signed-off-by: Sonu Saha <sonu.saha@progress.com> * DOCS: Extend test for introduced properties Signed-off-by: Sonu Saha <sonu.saha@progress.com> * FIX: Correct exception class to handle bad yaml Signed-off-by: Sonu Saha <sonu.saha@progress.com> * Doc Review Signed-off-by: Deepa Kumaraswamy <dkumaras@progress.com> * FIX: Handle specific exception to handle bad yaml Signed-off-by: Sonu Saha <sonu.saha@progress.com> Signed-off-by: Sonu Saha <sonu.saha@progress.com> Signed-off-by: Deepa Kumaraswamy <dkumaras@progress.com> Co-authored-by: Deepa Kumaraswamy <dkumaras@progress.com> Signed-off-by: Sonu Saha <sonu.saha@progress.com> Signed-off-by: Deepa Kumaraswamy <dkumaras@progress.com> Co-authored-by: Sonu Saha <98935583+ahasunos@users.noreply.github.com> Co-authored-by: Deepa Kumaraswamy <dkumaras@progress.com>
This commit is contained in:
parent
3e3b2c9b5b
commit
9e4c4994c6
6 changed files with 231 additions and 30 deletions
|
@ -11,40 +11,112 @@ platform = "linux"
|
||||||
parent = "inspec/resources/os"
|
parent = "inspec/resources/os"
|
||||||
+++
|
+++
|
||||||
|
|
||||||
Use the `lxc` Chef InSpec audit resource to test the information about Linux containers. LXC is a command-line client for LXD that manages your LXD instances (containers and virtual machines). The tests are against the container's information obtained on `lxc info [container-name]`. `lxc` resource allows the testing if the container exists or is in running status.
|
Use the `lxc` Chef InSpec audit resource to test the information about Linux containers. LXC is a command-line client for LXD that manages your LXD instances (containers and virtual machines). The tests are against the container's information obtained on `lxc info [container-name]`. `lxc` resource allows the testing if the container exists or is in *running* status.
|
||||||
|
|
||||||
## Availability
|
## Availability
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
This resource is distributed with Chef InSpec.
|
This resource is distributed with Chef InSpec and is automatically available for use.
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
An `lxc` Chef InSpec audit resource allows testing if the container exists or is in running status.
|
An `lxc` Chef InSpec audit resource allows testing if the container exists or is in *running* status.
|
||||||
|
|
||||||
|
```ruby
|
||||||
describe lxc("linux-container-name") do
|
describe lxc("linux-container-name") do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
it { should be_running }
|
it { should be_running }
|
||||||
end
|
end
|
||||||
|
```
|
||||||
|
|
||||||
## Matchers
|
## Matchers
|
||||||
|
|
||||||
For a full list of available matchers, please visit our [matchers page](https://docs.chef.io/inspec/matchers/).
|
For a full list of available matchers, please visit our [matchers page](https://docs.chef.io/inspec/matchers/).
|
||||||
|
|
||||||
The specific matchers of this resource are: `exist`, `be_running`.
|
The specific matchers of this resource are: `exist` and `be_running`.
|
||||||
|
|
||||||
### exist
|
### exist
|
||||||
|
|
||||||
The `exist` matcher is used to specify if the container exists:
|
The `exist` matcher is used to specify if the container exists:
|
||||||
|
|
||||||
|
```ruby
|
||||||
it { should exist }
|
it { should exist }
|
||||||
|
```
|
||||||
|
|
||||||
### be_running
|
### be_running
|
||||||
|
|
||||||
The `be_running` matcher is used to check if the container is running:
|
The `be_running` matcher is used to check if the container is running:
|
||||||
|
|
||||||
|
```ruby
|
||||||
it { should be_running }
|
it { should be_running }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### name
|
||||||
|
|
||||||
|
Returns the instance name.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("name") { should eq "ubuntu-container" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### status
|
||||||
|
|
||||||
|
Returns the instance status.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("status") { should cmp "Running" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### type
|
||||||
|
|
||||||
|
Returns the instance type (for example, container).
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("type") { should eq "container" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### architecture
|
||||||
|
|
||||||
|
Returns the architecture of the instance.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("architecture") { should eq "x86_64" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### pid
|
||||||
|
|
||||||
|
Returns the pid of the instance.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("pid") { should eq 1378 }
|
||||||
|
```
|
||||||
|
|
||||||
|
### created_at
|
||||||
|
|
||||||
|
Returns the creation date of the instance.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("created_at") { should eq "2022/08/16 12:07 UTC" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### last_used_at
|
||||||
|
|
||||||
|
Returns the last used date of the instance.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("last_used_at") { should eq "2022/08/17 05:06 UTC" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### resources
|
||||||
|
|
||||||
|
Returns the resource information of the instance.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("resources") { should include "Disk usage" }
|
||||||
|
```
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
@ -54,14 +126,37 @@ The following examples show how to use this Chef InSpec audit resource.
|
||||||
|
|
||||||
The below test passes if the container `immense-phoenix` exists as part of the LXD instances.
|
The below test passes if the container `immense-phoenix` exists as part of the LXD instances.
|
||||||
|
|
||||||
|
```ruby
|
||||||
describe lxc("immense-phoenix") do
|
describe lxc("immense-phoenix") do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
```
|
||||||
|
|
||||||
### Ensures container is in running status
|
### Ensures container is in running status
|
||||||
|
|
||||||
The below test passes if the container `delicate-sloth` exists as part of the LXD instances and the status is running.
|
The below test passes if the container `delicate-sloth` exists as part of the LXD instances and the status is running.
|
||||||
|
|
||||||
|
```ruby
|
||||||
describe lxc("delicate-sloth") do
|
describe lxc("delicate-sloth") do
|
||||||
it { should be_running }
|
it { should be_running }
|
||||||
end
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ensures container exists, is in running status, and verifies the different container properties
|
||||||
|
|
||||||
|
The below test passes if the container `ubuntu-container` exists, is running, and the properties value matches against the desired value.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe lxc("ubuntu-container") do
|
||||||
|
it { should exist }
|
||||||
|
it { should be_running }
|
||||||
|
its("name") { should eq "ubuntu-container" }
|
||||||
|
its("status") { should cmp "Running" }
|
||||||
|
its("type") { should eq "container" }
|
||||||
|
its("architecture") { should eq "x86_64" }
|
||||||
|
its("pid") { should eq 1378 }
|
||||||
|
its("created_at") { should eq "2022/08/16 12:07 UTC" }
|
||||||
|
its("last_used_at") { should eq "2022/08/17 05:06 UTC" }
|
||||||
|
its("resources") { should include "Disk usage" }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
|
@ -9,14 +9,26 @@ module Inspec::Resources
|
||||||
describe lxc("ubuntu-container") do
|
describe lxc("ubuntu-container") do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
it { should be_running }
|
it { should be_running }
|
||||||
|
its("name") { should eq "ubuntu-container" }
|
||||||
|
its("status") { should cmp "Running" }
|
||||||
|
its("type") { should eq "container" }
|
||||||
|
its("architecture") { should eq "x86_64" }
|
||||||
|
its("pid") { should eq 1378 }
|
||||||
|
its("created_at") { should eq "2022/08/16 12:07 UTC" }
|
||||||
|
its("last_used_at") { should eq "2022/08/17 05:06 UTC" }
|
||||||
|
its("resources") { should include "Disk usage" }
|
||||||
end
|
end
|
||||||
EXAMPLE
|
EXAMPLE
|
||||||
|
|
||||||
|
attr_reader :container_info, :container_name
|
||||||
|
|
||||||
# Resource initialization.
|
# Resource initialization.
|
||||||
def initialize(container_name)
|
def initialize(container_name)
|
||||||
@container_name = container_name
|
@container_name = container_name
|
||||||
|
|
||||||
raise Inspec::Exceptions::ResourceSkipped, "The `lxc` resource is not supported on your OS yet." unless inspec.os.linux?
|
raise Inspec::Exceptions::ResourceSkipped, "The `lxc` resource is not supported on your OS yet." unless inspec.os.linux?
|
||||||
|
|
||||||
|
@container_info = populate_container_info
|
||||||
end
|
end
|
||||||
|
|
||||||
def resource_id
|
def resource_id
|
||||||
|
@ -28,17 +40,60 @@ module Inspec::Resources
|
||||||
end
|
end
|
||||||
|
|
||||||
def exists?
|
def exists?
|
||||||
lxc_info_cmd.exit_status.to_i == 0
|
!@container_info.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def running?
|
def running?
|
||||||
container_info = lxc_info_cmd.stdout.split(":").map(&:strip)
|
@container_info.key?("Status") && @container_info["Status"].casecmp("Running") == 0
|
||||||
container_info[0] == "Status" && container_info[1] == "Running"
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
@container_info["Name"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def status
|
||||||
|
@container_info["Status"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
@container_info["Type"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def architecture
|
||||||
|
@container_info["Architecture"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def pid
|
||||||
|
@container_info["PID"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def created_at
|
||||||
|
@container_info["Created"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def last_used_at
|
||||||
|
@container_info["Last Used"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def resources
|
||||||
|
@container_info["Resources"]
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Method to find lxc
|
def populate_container_info
|
||||||
|
lxc_util = find_lxc_or_error
|
||||||
|
lxc_info_cmd = inspec.command("#{lxc_util} info #{@container_name}")
|
||||||
|
|
||||||
|
if lxc_info_cmd.exit_status.to_i == 0
|
||||||
|
parse_command_output(lxc_info_cmd.stdout)
|
||||||
|
elsif lxc_info_cmd.stderr =~ /Error: Instance not found/
|
||||||
|
{}
|
||||||
|
else
|
||||||
|
raise Inspec::Exceptions::ResourceFailed, "Unable to retrieve information for #{container_name}.\n#{lxc_info_cmd.stderr}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def find_lxc_or_error
|
def find_lxc_or_error
|
||||||
%w{/usr/sbin/lxc /sbin/lxc lxc}.each do |cmd|
|
%w{/usr/sbin/lxc /sbin/lxc lxc}.each do |cmd|
|
||||||
return cmd if inspec.command(cmd).exist?
|
return cmd if inspec.command(cmd).exist?
|
||||||
|
@ -47,11 +102,12 @@ module Inspec::Resources
|
||||||
raise Inspec::Exceptions::ResourceFailed, "Could not find `lxc`"
|
raise Inspec::Exceptions::ResourceFailed, "Could not find `lxc`"
|
||||||
end
|
end
|
||||||
|
|
||||||
def lxc_info_cmd
|
def parse_command_output(output)
|
||||||
bin = find_lxc_or_error
|
require "yaml" unless defined?(YAML)
|
||||||
info_cmd = "info #{@container_name} | grep -i Status"
|
YAML.load(output)
|
||||||
lxc_cmd = format("%s %s", bin, info_cmd).strip
|
rescue Psych::SyntaxError => e
|
||||||
inspec.command(lxc_cmd)
|
warn "Could not parse the command output.\n#{e.message}"
|
||||||
|
{}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
1
test/fixtures/cmd/lxcerror
vendored
Normal file
1
test/fixtures/cmd/lxcerror
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Error: Instance not found
|
43
test/fixtures/cmd/lxcinfo
vendored
43
test/fixtures/cmd/lxcinfo
vendored
|
@ -1 +1,42 @@
|
||||||
Status: Running
|
Name: ubuntu-container
|
||||||
|
Status: RUNNING
|
||||||
|
Type: container
|
||||||
|
Architecture: x86_64
|
||||||
|
PID: 1378
|
||||||
|
Created: 2022/08/16 12:07 UTC
|
||||||
|
Last Used: 2022/08/17 05:06 UTC
|
||||||
|
|
||||||
|
Resources:
|
||||||
|
Processes: 13
|
||||||
|
Disk usage:
|
||||||
|
root: 53.97MiB
|
||||||
|
CPU usage:
|
||||||
|
CPU usage (in seconds): 2
|
||||||
|
Memory usage:
|
||||||
|
Memory (current): 32.30MiB
|
||||||
|
Network usage:
|
||||||
|
eth0:
|
||||||
|
Type: broadcast
|
||||||
|
State: UP
|
||||||
|
Host interface: vethc32daefe
|
||||||
|
MAC address: 00:16:3e:0e:be:4b
|
||||||
|
MTU: 1500
|
||||||
|
Bytes received: 18.12kB
|
||||||
|
Bytes sent: 18.82kB
|
||||||
|
Packets received: 130
|
||||||
|
Packets sent: 183
|
||||||
|
IP addresses:
|
||||||
|
inet: 10.199.12.205/24 (global)
|
||||||
|
inet6: fd42:574e:edd0:2d9f:216:3eff:fe0e:be4b/64 (global)
|
||||||
|
inet6: fe80::216:3eff:fe0e:be4b/64 (link)
|
||||||
|
lo:
|
||||||
|
Type: loopback
|
||||||
|
State: UP
|
||||||
|
MTU: 65536
|
||||||
|
Bytes received: 0B
|
||||||
|
Bytes sent: 0B
|
||||||
|
Packets received: 0
|
||||||
|
Packets sent: 0
|
||||||
|
IP addresses:
|
||||||
|
inet: 127.0.0.1/8 (local)
|
||||||
|
inet6: ::1/128 (local)
|
|
@ -392,7 +392,8 @@ class MockLoader
|
||||||
"/usr/sbin/ipfstat -io" => cmd.call("ipfstat-io"),
|
"/usr/sbin/ipfstat -io" => cmd.call("ipfstat-io"),
|
||||||
%{type "/usr/sbin/ipfstat"} => empty.call,
|
%{type "/usr/sbin/ipfstat"} => empty.call,
|
||||||
# lxc
|
# lxc
|
||||||
"/usr/sbin/lxc info my-ubuntu-container | grep -i Status" => cmd.call("lxcinfo"),
|
"/usr/sbin/lxc info ubuntu-container" => cmd.call("lxcinfo"),
|
||||||
|
"/usr/sbin/lxc info my-ubuntu-container-1" => cmd_stderr.call("lxcerror"),
|
||||||
%{sh -c 'type "/usr/sbin/lxc"'} => empty.call,
|
%{sh -c 'type "/usr/sbin/lxc"'} => empty.call,
|
||||||
# cgroup
|
# cgroup
|
||||||
"cgget -n -a carrotking" => cmd.call("cgget-n-a"),
|
"cgget -n -a carrotking" => cmd.call("cgget-n-a"),
|
||||||
|
|
|
@ -8,14 +8,21 @@ require_relative "../../../lib/inspec/resources/lxc"
|
||||||
describe "Inspec::Resources::Lxc" do
|
describe "Inspec::Resources::Lxc" do
|
||||||
# ubuntu
|
# ubuntu
|
||||||
it "verify lxc resource on ubuntu" do
|
it "verify lxc resource on ubuntu" do
|
||||||
resource = MockLoader.new(:ubuntu).load_resource("lxc", "my-ubuntu-container")
|
resource = MockLoader.new(:ubuntu).load_resource("lxc", "ubuntu-container")
|
||||||
_(resource.exists?).must_equal true
|
_(resource.exists?).must_equal true
|
||||||
_(resource.running?).must_equal true
|
_(resource.running?).must_equal true
|
||||||
_(resource.resource_skipped?).must_equal false
|
_(resource.resource_skipped?).must_equal false
|
||||||
_(resource.resource_id).must_equal "my-ubuntu-container"
|
_(resource.name).must_equal "ubuntu-container"
|
||||||
|
_(resource.status).must_equal "RUNNING"
|
||||||
|
_(resource.type).must_equal "container"
|
||||||
|
_(resource.architecture).must_equal "x86_64"
|
||||||
|
_(resource.pid).must_equal 1378
|
||||||
|
_(resource.created_at).must_equal "2022/08/16 12:07 UTC"
|
||||||
|
_(resource.last_used_at).must_equal "2022/08/17 05:06 UTC"
|
||||||
|
_(resource.resource_id).must_equal "ubuntu-container"
|
||||||
end
|
end
|
||||||
|
|
||||||
# # ubuntu
|
# ubuntu
|
||||||
it "verify lxc resource on ubuntu for non exisiting container" do
|
it "verify lxc resource on ubuntu for non exisiting container" do
|
||||||
resource = MockLoader.new(:ubuntu).load_resource("lxc", "my-ubuntu-container-1")
|
resource = MockLoader.new(:ubuntu).load_resource("lxc", "my-ubuntu-container-1")
|
||||||
_(resource.exists?).must_equal false
|
_(resource.exists?).must_equal false
|
||||||
|
|
Loading…
Reference in a new issue