diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ffbd1b60ce..ed8e7392a7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,7 +33,7 @@ jobs: PGPASSWORD: smartvm CC_TEST_REPORTER_ID: "${{ secrets.CC_TEST_REPORTER_ID }}" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up system run: bin/before_install - name: Set up Ruby diff --git a/app/controllers/api/vms_controller.rb b/app/controllers/api/vms_controller.rb index 70bd334207..5c6de7d691 100644 --- a/app/controllers/api/vms_controller.rb +++ b/app/controllers/api/vms_controller.rb @@ -67,14 +67,6 @@ def set_owner_resource(type, id = nil, data = nil) end end - def add_lifecycle_event_resource(type, id = nil, data = nil) - lifecycle_event = lifecycle_event_from_data(data) - api_resource(type, id, "Adding Life Cycle Event #{lifecycle_event['event']} to") do |vm| - LifecycleEvent.create_event(vm, lifecycle_event) - {} - end - end - def scan_resource(type, id = nil, _data = nil) enqueue_ems_action(type, id, "Scanning", :method_name => "scan", :supports => :smartstate_analysis, :role => "smartstate") end @@ -234,14 +226,5 @@ def resize_resource(type, id, data) rescue => err action_result(false, err.to_s) end - - private - - def lifecycle_event_from_data(data) - data ||= {} - data = data.slice("event", "status", "message", "created_by") - data.keys.each { |k| data[k] = data[k].to_s } - data - end end end diff --git a/config/api.yml b/config/api.yml index 4847154ac8..46aa704935 100644 --- a/config/api.yml +++ b/config/api.yml @@ -4646,8 +4646,6 @@ - sui_vm_details_view - :name: edit :identifier: vm_edit - - :name: add_lifecycle_event - :identifier: vm_edit - :name: add_event :identifier: vm_edit - :name: check_compliance @@ -4728,8 +4726,6 @@ :post: - :name: edit :identifier: vm_edit - - :name: add_lifecycle_event - :identifier: vm_edit - :name: add_event :identifier: vm_edit - :name: check_compliance diff --git a/lib/api/filter.rb b/lib/api/filter.rb index 52337137a7..ef9d6db8f0 100644 --- a/lib/api/filter.rb +++ b/lib/api/filter.rb @@ -1,5 +1,6 @@ module Api class Filter + OPERATOR_REGEXP = /^ *([^=!>< ]+) *(!==?|[=!]~|[<>=]=?) *(.*?) *$/.freeze OPERATORS = { "!=" => {:default => "!=", :regex => "REGULAR EXPRESSION DOES NOT MATCH", :null => "IS NOT NULL"}, "<=" => {:default => "<="}, @@ -68,7 +69,6 @@ def parse_filter(filter) methods = OPERATORS[operator] is_regex = filter_value =~ /%|\*/ && methods[:regex] - str_method = is_regex ? methods[:regex] : methods[:default] filter_value, method = case filter_value when /^\[(.*)\]$/ @@ -82,8 +82,10 @@ def parse_filter(filter) unquoted_filter_value = $1 if filter_field.column_type == :string_set && methods[:string_set] [unquoted_filter_value, methods[:string_set]] + elsif is_regex + [unquoted_filter_value, methods[:regex]] else - [unquoted_filter_value, str_method] + [unquoted_filter_value, methods[:default]] end when /^(NULL|nil)$/i [nil, methods[:null] || methods[:default]] @@ -120,22 +122,13 @@ def single_expression(field, operator, value) end def split_filter_string(filter) - operator = nil - operators_from_longest_to_shortest = OPERATORS.keys.sort_by(&:size).reverse - filter.size.times do |i| - operator = operators_from_longest_to_shortest.detect do |o| - o == filter[(i..(i + o.size - 1))] - end - break if operator - end + filter_match = OPERATOR_REGEXP.match(filter) + filter_attr, operator, filter_value = filter_match&.captures - if operator.blank? + unless OPERATORS.key?(operator) raise BadRequestError, "Unknown operator specified in filter #{filter}" end - filter_attr, _op, filter_value = filter.partition(operator) - filter_value.strip! - filter_attr.strip! *associations, attr_name = filter_attr.split(".") [MiqExpression::Field.new(model, associations, attr_name), operator, filter_value] end diff --git a/spec/lib/api/filter_spec.rb b/spec/lib/api/filter_spec.rb index 31cc150470..b81bb0878e 100644 --- a/spec/lib/api/filter_spec.rb +++ b/spec/lib/api/filter_spec.rb @@ -406,4 +406,53 @@ expect(actual.exp).to eq(expected) end end + + describe "#split_filter_string (private)" do + let(:name_field) { MiqExpression::Field.new(Vm, [], "name") } + + Api::Filter::OPERATORS.each_key do |operator| + it "matches operator #{operator}" do + expect(split_filter_string("name#{operator}x")).to eq([name_field, operator, "x"]) + expect(split_filter_string("name#{operator}>x")).to eq([name_field, operator, ">x"]) + end + end + + it "parses parses associations" do + field = MiqExpression::Field.new(Vm, ["host"], "name") + expect(split_filter_string("host.name=x")).to eq([field, "=", "x"]) + end + + it "handles whitespace" do + expect(split_filter_string(" name = x ")).to eq([name_field, "=", "x"]) + end + + it "handles blank" do + expect(split_filter_string(" name = ")).to eq([name_field, "=", ""]) + end + + it "supports quotes" do + expect(split_filter_string(" name= \"x y\" ")).to eq([name_field, "=", "\"x y\""]) + expect(split_filter_string("name ='x y'")).to eq([name_field, "=", "'x y'"]) + end + + it "supports a non-operator that looks like an operator" do + expect(split_filter_string("name=~= x y ")).to eq([name_field, "=~", "= x y"]) + end + + [ + 'name^bb', + '=bb', + 'name', + ].each do |str| + it "complains about '#{str}'" do + expect do + split_filter_string(str) + end.to raise_error(Api::BadRequestError, /Unknown operator specified/) + end + end + + def split_filter_string(str) + described_class.new("", Vm).send(:split_filter_string, str) + end + end end diff --git a/spec/requests/vms_spec.rb b/spec/requests/vms_spec.rb index 8aea8cd705..26c9613892 100644 --- a/spec/requests/vms_spec.rb +++ b/spec/requests/vms_spec.rb @@ -1190,51 +1190,6 @@ def query_match_regexp(*tables) end end - context "Vm add_lifecycle_event action" do - let(:events) do - 1.upto(3).collect do |n| - {:event => "event#{n}", :status => "status#{n}", :message => "message#{n}", :created_by => "system"} - end - end - - it "add_lifecycle_event to an invalid vm" do - api_basic_authorize action_identifier(:vms, :add_lifecycle_event) - - post(invalid_vm_url, :params => gen_request(:add_lifecycle_event, :event => "event 1")) - - expect(response).to have_http_status(:not_found) - end - - it "add_lifecycle_event without appropriate action role" do - api_basic_authorize - - post(vm_url, :params => gen_request(:add_lifecycle_event, :event => "event 1")) - - expect(response).to have_http_status(:forbidden) - end - - it "add_lifecycle_event to a vm" do - api_basic_authorize action_identifier(:vms, :add_lifecycle_event) - - post(vm_url, :params => gen_request(:add_lifecycle_event, events[0])) - - expect_single_action_result(:success => true, :message => /adding life cycle event/i, :href => api_vm_url(nil, vm)) - expect(vm.lifecycle_events.size).to eq(1) - expect(vm.lifecycle_events.first.event).to eq(events[0][:event]) - end - - it "add_lifecycle_event to multiple vms" do - api_basic_authorize action_identifier(:vms, :add_lifecycle_event) - - post(api_vms_url, :params => gen_request(:add_lifecycle_event, - events.collect { |e| {:href => vm_url}.merge(e) })) - - expect_multiple_action_result(3, :success => true) - expect(vm.lifecycle_events.size).to eq(events.size) - expect(vm.lifecycle_events.collect(&:event)).to match_array(events.collect { |e| e[:event] }) - end - end - context "Vm scan action" do it "scans an invalid vm" do api_basic_authorize action_identifier(:vms, :scan)