Ask Your Question
0

Custom Type & Provider - self.instances JSON Issues

asked 2017-01-23 22:27:13 -0500

ross.murray gravatar image

I am working on a new custom provider for IIS, forked from the forge module puppet/iis. I am trying to make the module work for some of the older OS that I have to manage, which unfortunately are running Powershell 2.0. I have had it working in Puppet 2016.2 but everything fell apart when I upgraded the Master to 2016.5.1, and rather than keep my 'hacked together' version of the module I've started to re-do it to my needs from the ground up (re-using what I can, learning as I go) following the rather handy "Puppet Types & Providers" book by Dan Bode & Nan Liu.

Okay enough pretext. I am running into an issue implementing the self.instances method. Here is what I have been working with.

require 'json'
# snap_mod global variable decides whether to import the WebAdministration module, or add the WebAdministration snap-in.
$snap_mod = "$psver = [int]$PSVersionTable.PSVersion.Major; If($psver -lt 4){Add-PSSnapin WebAdministration}else{Import-Module WebAdministration}"
...

  def self.instances
    # Powershell could convert this output to JSON, but only from PS3.0 onwards (ConvertTo-JSON). 
    # For maximum compatibility we will have Ruby do it.
    inst_cmd = "#$snap_mod; Get-ChildItem 'IIS:\\sites' | ForEach-Object {Get-ItemProperty $_.PSPath | Select name, physicalPath, applicationPool, hostHeader, state, bindings}"
    # Must pass the .parse method an array, so we turn inst_cmd into an array, run it, convert the result to JSON and select the first array result...
    resp = Puppet::Type::Iis_site::ProviderPowershell.run(inst_cmd)
    site_json = JSON.parse(["#{resp}"].to_json).first
    site_json = [site_json] #if site_json.is_a?(Hash)
    site_json.map do |site|
      site_hash               = {}
      site_hash[:ensure]      = :present
      site_hash[:state]       = site['state']
      site_hash[:name]        = site['name']
      site_hash[:path]        = site['physicalPath']
      site_hash[:app_pool]    = site['applicationPool']
      binding_collection      = site['bindings']['Collection']
      bindings                = binding_collection.first['bindingInformation']
      site_hash[:protocol]    = site['bindings']['Collection'].first['protocol']
      site_hash[:ip]          = bindings.split(':')[0]
      site_hash[:port]        = bindings.split(':')[1]
      site_hash[:host_header] = bindings.split(':')[2]
      site_hash[:ssl]         = if site['bindings']['Collection'].first['sslFlags'].zero?
                                  :false
                                else
                                  :true
                                end
      new(site_hash)
    end
  end

The trouble I've encountered is that the .to_json method needs to be given an array. However no matter how I try to do this, something else doesn't work. When I provide it an array (as per example above) the .first method breaks. When I also provide that an array, the .map method breaks.

I am new to Ruby as I'm sure you've guessed. I am well aware there are likely several issues here rather than one. Any assistance would be a huge help.


My trouble has been

edit retag flag offensive close merge delete

Comments

1

You could take two different approaches to debugging it to help you see the shape of the actual structure.. you either could 'mock up' what you are doing in irb, where each return value will print out on your return line and allow you to execute commands against it manually, or you could ...

DarylW gravatar imageDarylW ( 2017-01-24 09:35:33 -0500 )edit
1

add in a `require 'pry'` and put In a `binding.pry()` and use pry to debug what is actually going on. http://pryrepl.org/ . If you add in an example of the structure of the json, we could help figure out your issue

DarylW gravatar imageDarylW ( 2017-01-24 09:38:19 -0500 )edit
1

As an FYI, I can pass in a string representation of the json returned from the awscli which is a hash structure, not an array, so JSON.parse should be able to take it just fine.

DarylW gravatar imageDarylW ( 2017-01-24 09:41:49 -0500 )edit

1 Answer

Sort by ยป oldest newest most voted
0

answered 2017-01-24 10:00:53 -0500

DarylW gravatar image

updated 2017-01-24 10:01:12 -0500

Based on the error message you linked, you are getting that error because the value that you are getting back is a string that doesn't parse to json.

You can see this by trying the following. run irb in your shell, then require 'json'

If you try passing just a string, via JSON.parse('foo') you will see an error like "JSON::ParserError: 757 unexpected token at 'foo'"

If you use your 'embed into an array' method, via JSON.parse(['foo'].to_json) you will get a return value of => ["foo"], showing that it just injects the string into an array structure. Even if you put a 'json' string into array brackets like that, you still won't get the behavior you are expecting... e.g. JSON.parse(['{}'].to_json) returns => ["{}"], which is the string '{}' inside of an array

Here are some links to understanding how to handle json strings in ruby http://stackoverflow.com/questions/54... http://ruby-doc.org/stdlib-1.9.3/libd...

edit flag offensive delete link more

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower

Stats

Asked: 2017-01-23 22:09:50 -0500

Seen: 23 times

Last updated: Jan 24