From 31bbb44da4c9a830cac4bf6e9b7600d21b2b188a Mon Sep 17 00:00:00 2001 From: Nik08 Date: Mon, 14 Aug 2023 14:21:42 +0530 Subject: [PATCH 1/6] Enabled using chef license key and server url config block Signed-off-by: Nik08 --- components/ruby/lib/chef-licensing/config.rb | 2 +- .../lib/chef-licensing/license_key_fetcher.rb | 19 +++++++++++++++++-- .../license_key_fetcher/file.rb | 2 ++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/components/ruby/lib/chef-licensing/config.rb b/components/ruby/lib/chef-licensing/config.rb index 6f415f2f..9dc34968 100644 --- a/components/ruby/lib/chef-licensing/config.rb +++ b/components/ruby/lib/chef-licensing/config.rb @@ -16,7 +16,7 @@ class << self attr_writer :license_server_url, :logger, :output, :license_server_url_check_in_file # is_local_license_service is used by context class - attr_accessor :is_local_license_service, :chef_entitlement_id, :chef_product_name, :chef_executable_name + attr_accessor :is_local_license_service, :chef_entitlement_id, :chef_product_name, :chef_executable_name, :chef_license_key, :license_server_url_in_config_file def license_server_url(opts = {}) return @license_server_url if @license_server_url && @license_server_url_check_in_file diff --git a/components/ruby/lib/chef-licensing/license_key_fetcher.rb b/components/ruby/lib/chef-licensing/license_key_fetcher.rb index 398fd03d..3c10fb2b 100644 --- a/components/ruby/lib/chef-licensing/license_key_fetcher.rb +++ b/components/ruby/lib/chef-licensing/license_key_fetcher.rb @@ -95,6 +95,15 @@ def perform_on_prem_operations end def perform_global_operations + logger.debug "License Key fetcher examining config values" + new_keys = fetch_license_key_from_config + license_type = validate_and_fetch_license_type(new_keys) + if license_type && !unrestricted_license_added?(new_keys, license_type) + # break the flow after the prompt if there is a restriction in adding license + # and return the license keys persisted in the file or @license_keys if any + return license_keys + end + logger.debug "License Key fetcher examining CLI arg checks" new_keys = fetch_license_key_from_arg license_type = validate_and_fetch_license_type(new_keys) @@ -106,6 +115,7 @@ def perform_global_operations logger.debug "License Key fetcher examining ENV checks" new_keys = fetch_license_key_from_env + # require "pry"; binding.pry license_type = validate_and_fetch_license_type(new_keys) if license_type && !unrestricted_license_added?(new_keys, license_type) # break the flow after the prompt if there is a restriction in adding license @@ -161,11 +171,11 @@ def add_license end end - # Note: Fetching from arg and env as well, to be able to fetch license when disk is non-writable + # Note: Fetching from arg, env and config as well, to be able to fetch license when disk is non-writable def fetch # While using on-prem licensing service, @license_keys have been fetched from API # While using global licensing service, @license_keys have been fetched from file - (fetch_license_key_from_arg << fetch_license_key_from_env << @license_keys).flatten.uniq + (fetch_license_key_from_arg << fetch_license_key_from_env << fetch_license_key_from_config << @license_keys).flatten.uniq end def self.fetch_and_persist(opts = {}) @@ -259,6 +269,11 @@ def fetch_license_key_from_env validate_license_key_format(new_key) end + def fetch_license_key_from_config + new_key = ChefLicensing::Config.chef_license_key + validate_license_key_format(new_key) + end + def validate_license_key_format(license_key) return [] if license_key.nil? diff --git a/components/ruby/lib/chef-licensing/license_key_fetcher/file.rb b/components/ruby/lib/chef-licensing/license_key_fetcher/file.rb index 3f9df116..c01c949d 100644 --- a/components/ruby/lib/chef-licensing/license_key_fetcher/file.rb +++ b/components/ruby/lib/chef-licensing/license_key_fetcher/file.rb @@ -131,6 +131,8 @@ def fetch_or_persist_url(license_server_url_from_config, license_server_url_from load_basic_license_data_to_contents(url, []) elsif @contents && license_server_url_from_system && license_server_url_from_system != @contents[:license_server_url] @contents[:license_server_url] = license_server_url_from_system + elsif @contents && ChefLicensing::Config.license_server_url_in_config_file && (license_server_url_from_config && license_server_url_from_config != @contents[:license_server_url]) + @contents[:license_server_url] = license_server_url_from_config end # Ensure the license server URL is returned to the caller in all cases From b3b3f223716e3b01a934ed79a4b20daf41606080 Mon Sep 17 00:00:00 2001 From: Nik08 Date: Mon, 14 Aug 2023 14:22:37 +0530 Subject: [PATCH 2/6] Test integration to validate using chef license url from config block Signed-off-by: Nik08 --- components/ruby/spec/config_spec.rb | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/components/ruby/spec/config_spec.rb b/components/ruby/spec/config_spec.rb index 1816ce70..64f9d407 100644 --- a/components/ruby/spec/config_spec.rb +++ b/components/ruby/spec/config_spec.rb @@ -90,5 +90,34 @@ ARGV.clear end end + + context "updating values in licenses.yaml file for license server url via config" do + let(:temp_dir) { Dir.mktmpdir } + let(:original_file) { "spec/fixtures/license_file_with_server_url/licenses.yaml" } + + before do + FileUtils.cp(original_file, "#{temp_dir}/licenses.yaml") + ChefLicensing.configure do |config| + config.license_server_url_check_in_file = false + config.license_server_url_in_config_file = true + config.license_server_url = "https://custom-licensing-server-2.com/License" + end + end + + let(:opts) { + { + dir: "#{temp_dir}", + } + } + + it "updates the value in licenses.yaml file" do + # load the original file first and check the value + expect(YAML.load_file("#{temp_dir}/licenses.yaml")[:license_server_url]).to eq("https://custom-licensing-server.com/License") + # this will update the value in licenses.yaml file + expect(ChefLicensing::Config.license_server_url(opts)).to eq("https://custom-licensing-server-2.com/License") + # load the file again and check the value + expect(YAML.load_file("#{temp_dir}/licenses.yaml")[:license_server_url]).to eq("https://custom-licensing-server-2.com/License") + end + end end end \ No newline at end of file From d9d51c7ddfb290a075ad9ee2739ffc9611010ed2 Mon Sep 17 00:00:00 2001 From: Nik08 Date: Mon, 14 Aug 2023 14:23:41 +0530 Subject: [PATCH 3/6] Test integration to validate setting license key using config block Signed-off-by: Nik08 --- .../ruby/spec/license_key_fetcher_spec.rb | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/components/ruby/spec/license_key_fetcher_spec.rb b/components/ruby/spec/license_key_fetcher_spec.rb index e677b802..ab723d92 100644 --- a/components/ruby/spec/license_key_fetcher_spec.rb +++ b/components/ruby/spec/license_key_fetcher_spec.rb @@ -267,6 +267,163 @@ end end + context "the license is set via config" do + let(:license_keys) { ["tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150"] } + let(:argv) { [] } + let(:env) { {} } + before do + ChefLicensing.configure do |config| + config.chef_license_key = "tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150" + end + ChefLicensing::Context.current_context = nil + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/listLicenses") + .to_return(body: { data: [], status_code: 404 }.to_json, + headers: { content_type: "application/json" }) + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/validate") + .with(query: { licenseId: "tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150", version: api_version }) + .to_return(body: { data: true, message: "License Id is valid", status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/client") + .with(query: { licenseId: "tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150", entitlementId: ChefLicensing::Config.chef_entitlement_id }) + .to_return(body: { data: client_api_data, status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/client") + .with(query: { licenseId: license_keys.join(","), entitlementId: ChefLicensing::Config.chef_entitlement_id }) + .to_return(body: { data: client_api_data, status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/desc") + .with(query: { licenseId: "tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150", entitlementId: ChefLicensing::Config.chef_entitlement_id }) + .to_return(body: { data: describe_api_data, status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + end + Dir.mktmpdir do |tmpdir| + let(:opts) { + { + logger: logger, + argv: argv, + env: env, + output: output, + dir: tmpdir, + } + } + + let(:license_key_fetcher) { described_class.new(opts) } + it "returns license key set using config" do + expect(license_key_fetcher.fetch_and_persist).to eq(["tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150"]) + end + end + end + + context "the license is set via env and config" do + let(:argv) { [] } + let(:env) { { "CHEF_LICENSE_KEY" => "free-c0832d2d-1111-1ec1-b1e5-011d182dc341-111" } } + let(:license_keys) { + %w{tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150 free-c0832d2d-1111-1ec1-b1e5-011d182dc341-111} + } + before do + ChefLicensing.configure do |config| + config.is_local_license_service = nil + config.chef_license_key = "tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150" + end + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/validate") + .with(query: { licenseId: "tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150", version: api_version }) + .to_return(body: { data: true, message: "License Id is valid", status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/validate") + .with(query: { licenseId: "free-c0832d2d-1111-1ec1-b1e5-011d182dc341-111", version: api_version }) + .to_return(body: { data: true, message: "License Id is valid", status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/client") + .with(query: { licenseId: "tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150", entitlementId: ChefLicensing::Config.chef_entitlement_id }) + .to_return(body: { data: client_api_data, status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/client") + .with(query: { licenseId: "free-c0832d2d-1111-1ec1-b1e5-011d182dc341-111", entitlementId: ChefLicensing::Config.chef_entitlement_id }) + .to_return(body: { data: client_api_data, status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/client") + .with(query: { licenseId: license_keys.join(","), entitlementId: ChefLicensing::Config.chef_entitlement_id }) + .to_return(body: { data: client_api_data, status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/desc") + .with(query: { licenseId: "tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150", entitlementId: ChefLicensing::Config.chef_entitlement_id }) + .to_return(body: { data: describe_api_data, status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + end + + Dir.mktmpdir do |tmpdir| + let(:opts) { + { + logger: logger, + argv: argv, + env: env, + output: output, + dir: tmpdir, + } + } + + let(:license_key_fetcher) { described_class.new(opts) } + it "returns only trial set in config and not free due to active trial restriction" do + expect(license_key_fetcher.fetch_and_persist).to eq(%w{tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150}) + end + end + end + + context "the license is set via argument and config" do + let(:env) { {} } + let(:argv) { ["--chef-license-key=free-c0832d2d-1111-1ec1-b1e5-011d182dc341-111"] } + let(:license_keys) { + %w{tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150 free-c0832d2d-1111-1ec1-b1e5-011d182dc341-111} + } + before do + ChefLicensing.configure do |config| + config.is_local_license_service = nil + config.chef_license_key = "tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150" + end + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/validate") + .with(query: { licenseId: "tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150", version: api_version }) + .to_return(body: { data: true, message: "License Id is valid", status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/validate") + .with(query: { licenseId: "free-c0832d2d-1111-1ec1-b1e5-011d182dc341-111", version: api_version }) + .to_return(body: { data: true, message: "License Id is valid", status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/client") + .with(query: { licenseId: "tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150", entitlementId: ChefLicensing::Config.chef_entitlement_id }) + .to_return(body: { data: client_api_data, status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/client") + .with(query: { licenseId: "free-c0832d2d-1111-1ec1-b1e5-011d182dc341-111", entitlementId: ChefLicensing::Config.chef_entitlement_id }) + .to_return(body: { data: client_api_data, status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/client") + .with(query: { licenseId: license_keys.join(","), entitlementId: ChefLicensing::Config.chef_entitlement_id }) + .to_return(body: { data: client_api_data, status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/desc") + .with(query: { licenseId: "tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150", entitlementId: ChefLicensing::Config.chef_entitlement_id }) + .to_return(body: { data: describe_api_data, status_code: 200 }.to_json, + headers: { content_type: "application/json" }) + end + + Dir.mktmpdir do |tmpdir| + let(:opts) { + { + logger: logger, + argv: argv, + env: env, + output: output, + dir: tmpdir, + } + } + + let(:license_key_fetcher) { described_class.new(opts) } + it "returns only trial set in config and not free due to active trial restriction" do + expect(license_key_fetcher.fetch_and_persist).to eq(%w{tmns-0f76efaf-b45b-4d92-86b2-2d144ce73dfa-150}) + end + end + end + context "multiple free licenses are restricted and can only add one free license in file" do let(:argv) { ["--chef-license-key=free-c0832d2d-1111-1ec1-b1e5-011d182dc341-112"] } @@ -343,6 +500,9 @@ } before do + ChefLicensing.configure do |config| + config.chef_license_key = nil + end stub_request(:get, "#{ChefLicensing::Config.license_server_url}/v1/validate") .with(query: { licenseId: "free-c0832d2d-1111-1ec1-b1e5-011d182dc341-111", version: api_version }) .to_return(body: { data: true, message: "License Id is valid", status_code: 200 }.to_json, From 15e568634c724462a7c39b8e3e989d057d045701 Mon Sep 17 00:00:00 2001 From: Nik08 Date: Mon, 14 Aug 2023 14:24:16 +0530 Subject: [PATCH 4/6] Doc change explaining usage of chef license key and license server url using config block Signed-off-by: Nik08 --- components/ruby/README.md | 6 ++++++ components/ruby/lib/chef-licensing/license_key_fetcher.rb | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/components/ruby/README.md b/components/ruby/README.md index 59096b35..0f033621 100644 --- a/components/ruby/README.md +++ b/components/ruby/README.md @@ -81,10 +81,16 @@ ChefLicensing.configure do |config| config.chef_product_name = "chef" config.chef_executable_name = "inspec" config.chef_entitlement_id = "chef123" + config.chef_license_key="free-t0832est-1111-1te1-b1e5-011t182test3-111" + config.license_server_url_in_config_file = true config.logger = Logger.new($stdout) end ``` +where: + +- `chef_license_key`: the unique License key which validates software entitlement to the Chef's Software. +- `license_server_url_in_config_file`: a boolean flag set when license server url to be used from config block. ## Usage diff --git a/components/ruby/lib/chef-licensing/license_key_fetcher.rb b/components/ruby/lib/chef-licensing/license_key_fetcher.rb index 3c10fb2b..98103411 100644 --- a/components/ruby/lib/chef-licensing/license_key_fetcher.rb +++ b/components/ruby/lib/chef-licensing/license_key_fetcher.rb @@ -115,7 +115,6 @@ def perform_global_operations logger.debug "License Key fetcher examining ENV checks" new_keys = fetch_license_key_from_env - # require "pry"; binding.pry license_type = validate_and_fetch_license_type(new_keys) if license_type && !unrestricted_license_added?(new_keys, license_type) # break the flow after the prompt if there is a restriction in adding license From 991052fcd4e16c0496d30e2ec266a4e880f387fd Mon Sep 17 00:00:00 2001 From: Nik08 Date: Thu, 17 Aug 2023 15:23:08 +0530 Subject: [PATCH 5/6] Raise error in software entitlement check when license keys are empty Signed-off-by: Nik08 --- components/ruby/lib/chef-licensing.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/ruby/lib/chef-licensing.rb b/components/ruby/lib/chef-licensing.rb index ba6f6e8c..0cb78e08 100644 --- a/components/ruby/lib/chef-licensing.rb +++ b/components/ruby/lib/chef-licensing.rb @@ -33,6 +33,8 @@ def check_feature_entitlement!(feature_name: nil, feature_id: nil) end def check_software_entitlement! + raise LicenseKeyFetcher::LicenseKeyNotFetchedError.new("Unable to obtain a License Key.") if license_keys.empty? + # If API call is not breaking that means license is entitled. client(license_keys: license_keys) true From 1ee9092869fb4b34cb6abb4331b9e3ec43515e7e Mon Sep 17 00:00:00 2001 From: Nik08 Date: Thu, 17 Aug 2023 17:52:07 +0530 Subject: [PATCH 6/6] Doc update to clarify usage of extra flag to reset chef_server_url Signed-off-by: Nik08 --- components/ruby/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/ruby/README.md b/components/ruby/README.md index 0f033621..6fda4db6 100644 --- a/components/ruby/README.md +++ b/components/ruby/README.md @@ -90,7 +90,7 @@ end where: - `chef_license_key`: the unique License key which validates software entitlement to the Chef's Software. -- `license_server_url_in_config_file`: a boolean flag set when license server url to be used from config block. +- `license_server_url_in_config_file`: a boolean flag when license server url needs to be reset from config block. ## Usage