-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Missing support for Q ports in API300::Synergy::LIGUplinkSet, missing support for multiple Synergy frames #216
Comments
I suppose that API300:Synergy::LIGUplinkSet should contain something like: def add_uplink(bay, port, icm_model, enclosure_index = 1)
enclosure_index = -1 if icm_model.include?('Virtual Connect SE 16Gb FC Module for Synergy')
entry = {
'desiredSpeed' => 'Auto',
'logicalLocation' => {
'locationEntries' => [
{ 'relativeValue' => bay, 'type' => 'Bay' },
{ 'relativeValue' => enclosure_index, 'type' => 'Enclosure' },
{ 'relativeValue' => relative_value_of(port, icm_model), 'type' => 'Port' }
]
}
}
@data['logicalPortConfigInfos'] << entry
end
def relative_value_of(port, icm_model)
# Virtual Connect SE 40Gb F8 Module for Synergy
# Virtual Connect SE 16Gb FC Module for Synergy
# insert logic here!
end I'm working on some draft. Will send next update soon. |
This might be the solution for both Synergy modules which can have some uplink ports. I'm not so sure about hard-coded names of Modules ... on the other hand there's probably no other option as we are creating template only. def add_uplink(bay, port, icm_model, enclosure_index = 1)
enclosure_index = -1 if icm_model.include?('Virtual Connect SE 16Gb FC Module for Synergy')
entry = {
'desiredSpeed' => 'Auto',
'logicalLocation' => {
'locationEntries' => [
{ 'relativeValue' => bay, 'type' => 'Bay' },
{ 'relativeValue' => enclosure_index, 'type' => 'Enclosure' },
{ 'relativeValue' => relative_value_of(port, icm_model), 'type' => 'Port' }
]
}
}
@data['logicalPortConfigInfos'] << entry
end
def relative_value_of(port, icm_model)
port_sep = port.match( /[^[:alnum:]]/ ).to_s
port_cur = port_sep.empty? ? port : port.split(port_sep)[0]
port_add = port_sep.empty? ? 0 : port.split(port_sep)[1].to_i
if icm_model.includes?('Virtual Connect SE 40Gb F8 Module for Synergy')
port_number = port_cur.gsub(/[^\d]/, '').to_i
return (61 + ((port_number - 1) * 5) + port_add)
end
if icm_model.includes?('Virtual Connect SE 16Gb FC Module for Synergy')
if port_sep.empty?
return 12 + port_cur.gsub(/[^\d]/, '').to_i
else
port_number = port_cur.gsub(/[^\d]/, '').to_i
return (20 + ((port_number - 1) * 4) + port_add)
end
end
raise "Unsupported ICM model #{icm_model}"
end |
@vranystepan , what about something like this:? def add_uplink(bay, port, enclosure_index = 1)
entry = {
'desiredSpeed' => 'Auto',
'logicalLocation' => {
'locationEntries' => [
{ 'relativeValue' => bay, 'type' => 'Bay' },
{ 'relativeValue' => enclosure_index, 'type' => 'Enclosure' },
{ 'relativeValue' => relative_value_of(port, enclosure_index), 'type' => 'Port' }
]
}
}
@data['logicalPortConfigInfos'] << entry
end
def relative_value_of(port, enclosure_index = 1)
match = port.match(/^([A-Za-z])[:\.]?(\d+)[:\.]?(\d*)$/)
raise(InvalidResource, 'Invalid port format. Should look similar to D1 or Q1.2') unless match
identifier, offset, offset2 = match.captures
case identifier.upcase
when 'D' then offset.to_i
when 'X' then 16 + offset.to_i
when 'Q'
if enclosure_index = -1 # Virtual Connect SE 16Gb FC Module for Synergy
20 + (offset.to_i - 1) * 4 + offset2.to_i
else # Virtual Connect SE 40Gb F8 Module for Synergy
61 + (offset.to_i - 1) * 5 + offset2.to_i
end
else raise(InvalidResource, "Port not supported: #{identifier} type not found")
end
end It returns: relative_value_of('X2:1') # 18
relative_value_of('X2:2') # 18
relative_value_of('Q1') # 61
relative_value_of('Q2') # 66
relative_value_of('Q2:2') # 68
relative_value_of('Q1', -1) # 20
relative_value_of('Q1:1', -1) # 21
relative_value_of('Q2:1', -1) # 25
relative_value_of('Q4:1', -1) # 33 I'm not sure if it's enough to just pass the enclosure_index, but for this case, if the 16GB module is the only one that has a Also, what are SFP+ ports, and where are you finding the values for all these different port values? |
@jsmartt I like your code! Nice and Clean 👍 Yes, you're right, -1 is valid only for FC modules, so this condition will work. I'll test it tomorrow in the actual environment. All these values come from LIGs created through web interface. So I'm basically fetching them from API. I've just realized that I need to double check behaviour of Q ports (40GbVC) when they are configured as FC or FCoE uplinks. Logically they should have the same relative indexes ... but you never know.
|
I've done doublecheck. Port numbering is the same even for FC uplinks. So |
Cool. @vranystepan , were you planning on implementing this feature, or shall I (or someone else)? |
@jsmartt I will try to implement it. One question. Is it API200 or API300/Synergy? I suppose we should place it into the Synergy since there are also C7000 modules with Q modules ( So what about
def add_uplink(bay, port, enclosure_index = 1)
entry = {
'desiredSpeed' => 'Auto',
'logicalLocation' => {
'locationEntries' => [
{ 'relativeValue' => bay, 'type' => 'Bay' },
{ 'relativeValue' => enclosure_index, 'type' => 'Enclosure' },
{ 'relativeValue' => relative_value_of(port, enclosure_index), 'type' => 'Port' }
]
}
}
@data['logicalPortConfigInfos'] << entry
end
def relative_value_of(port, enclosure_index = 1)
match = port.match(/^([A-Za-z])[:\.]?(\d+)[:\.]?(\d*)$/)
raise(InvalidResource, 'Invalid port format. Should look similar to D1 or Q1.2') unless match
identifier, offset, offset2 = match.captures
case identifier.upcase
when 'D' then offset.to_i
when 'X' then 16 + offset.to_i
when 'Q'
if enclosure_index = -1 # Virtual Connect SE 16Gb FC Module for Synergy
20 + (offset.to_i - 1) * 4 + offset2.to_i
else # Virtual Connect SE 40Gb F8 Module for Synergy
61 + (offset.to_i - 1) * 5 + offset2.to_i
end
else raise(InvalidResource, "Port not supported: #{identifier} type not found")
end
end
|
I don't see why not just add it to API200 only and let the API300 variant classes inherit it. If OneView API v200 doesn't support an offset that the user passes, it will notify the user, so we wouldn't have to worry about that logic. But keeping them all the same will reduce confusion and difficulties with the methods having different parameters. And if the offsets are different in Synergy and C7000 we can set a class constant that can be used in the method(s) so we don't have to re-define them. Does that sound reasonable? |
Absolutely. Perhaps I'll try it with something like self.class.to_s.include? 'C7000' |
@jsmartt Couple points about
So Q-ports may be handled this way: start = self.class.to_s.include?('Synergy') ? 61 : 16
start + (offset.to_i - 1) * 5 + offset2.to_i But how to handle different relative positions of X port across various ICM models (for c-class enclosures) ... |
Can I take a step back here and ask @tmiotto, @fgbulsoni , @ricardogpsf & @aalexmonteiro why exactly we're doing this conversion in the first place? It looks like the API docs accept the value as strings like "Q1.2", so why go through the effort to convert it to an integer? I see it shown as an integer on the GET of a LIG, but the GET for an UplinkSet shows it as a string. The user doesn't care how this gets handled on the back-end, so why do this conversion at all? I know very little about LIGs, so pardon my ignorance if it shows here. |
@jsmartt It is because if you try to handle it within the LIG it must be an integer. This conversion is not for the user, it is used internally by the SDK. |
😞 bummer |
The preferred method is to first:
Then, look within This is what I do within the |
BTW, you can ask the caller for the Interconnect Module name so you can look up the module object from the API. OR, you ask for the LIG from the user, which then you look for the |
That's brilliant! Thank you. For example: Returns: {
"type": "InterconnectTypeCollectionV300",
"members": [
{
"type": "interconnect-typeV300",
"partNumber": "794502-B23",
"minimumFirmwareVersion": "1.0.0",
"portInfos": [
{
"portName": "Q8:1",
"portNumber": 97,
"uplinkCapable": false,
"portCapability": [
"Ethernet",
"Stacking"
],
... However we'll need to pass |
@jsmartt, @fgbulsoni, Test file: # Logical Interconnect Group in the second Bay Set
lig = OneviewSDK::API300::Synergy::LogicalInterconnectGroup.new(c, {
name: 'LIG-40gb-1Frame-Redundant-01',
redundancyType: 'Redundant',
interconnectBaySet: 2,
enclosureType: "SY12000",
enclosureIndexes: [1]
})
# One tagged network / VLAN
mgmt_network = OneviewSDK::API300::EthernetNetwork.new(c, { name: 'Management', vlanId: 1000, purpose: 'General', smartLink: false, privateNetwork: false })
mgmt_network.create
lig.add_network(mgmt_network)
# Two Fourty-gig modules
lig.add_interconnect(2, 'Virtual Connect SE 40Gb F8 Module for Synergy', nil, 1)
lig.add_interconnect(5, 'Virtual Connect SE 40Gb F8 Module for Synergy', nil, 1)
# One Uplink Set
uplink_set = OneviewSDK::API300::LIGUplinkSet.new(c, {
name: 'UplinkSet1',
networkType: 'Ethernet',
primaryPort: nil
})
# Two uplink ports
uplink_set.add_uplink(2,'Q1', 'Virtual Connect SE 40Gb F8 Module for Synergy')
uplink_set.add_uplink(5,'Q1', 'Virtual Connect SE 40Gb F8 Module for Synergy')
# Add Uplink Set to the Logical Interconnect Group
lig.add_uplink_set(uplink_set)
# Create Logical Interconnect Group
lig.create api200/lig_uplink_set.rb: ...
# Specify one uplink passing the virtual connect bay and the port to be attached.
# @param [Fixnum] bay number to identify the VC
# @param [String] port to attach the uplink. Allowed D1..D16 and X1..X10
def add_uplink(bay, port, model = nil, enclosure_index = nil)
enclosure_index ||= model.include?('Virtual Connect SE 16Gb FC Module') ? -1 : 1
if model
port = fetch_relative_value_of(port, model)
else
port = (port.to_s == port.to_i.to_s) ? port : relative_value_of(port)
end
entry = {
'desiredSpeed' => 'Auto',
'logicalLocation' => {
'locationEntries' => [
{ 'relativeValue' => bay, 'type' => 'Bay' },
{ 'relativeValue' => enclosure_index, 'type' => 'Enclosure' },
{ 'relativeValue' => port, 'type' => 'Port' }
]
}
}
@data['logicalPortConfigInfos'] << entry
end
...
def fetch_relative_value_of(port, model)
port = port.sub('.',':') # normalize naming if needed
interconnect_type = OneviewSDK::Interconnect.get_type(@client, model)
unless interconnect_type
list = OneviewSDK::Interconnect.get_types(@client).map { |t| t['name'] }
raise OneviewSDK::NotFound, "Interconnect type #{type} not found! Supported types: #{list}"
end
type_port = interconnect_type['portInfos'].find { |p| p['portName'] == port }
type_port['portNumber']
end Unfortunately I don't have OneView 2.0 with c7000 or OneView 3.0 with c7000 to test other scenarios :( Another possible solution would be to merge these classes to |
Nice! That looks promising. If that method needs to be used in 2 separate resources, you may also want to consider making it a class method (with or without an instance method that wraps it). As for the c7000 HW, can you use the simulator to get what you need? |
I've just realized that that I need just OneView Virtual Machines without hardware. Will do some functionality tests. At this point I don't think we need to call this method from more resources, I was just thinking about Also, I forgot to add |
@jsmartt @fgbulsoni, Anyway these mothods should be able to handle all 3 scenarios:
add_uplink method: def add_uplink(bay, port, model = nil, enclosure_index = nil)
enclosure_index ||= model.include?('Virtual Connect SE 16Gb FC Module') ? -1 : 1
port =
if model
fetch_relative_value_of(port, model)
else
port.to_s == port.to_i.to_s ? port : relative_value_of(port)
end
entry = {
'desiredSpeed' => 'Auto',
'logicalLocation' => {
'locationEntries' => [
{ 'relativeValue' => bay, 'type' => 'Bay' },
{ 'relativeValue' => enclosure_index, 'type' => 'Enclosure' },
{ 'relativeValue' => port, 'type' => 'Port' }
]
}
}
@data['logicalPortConfigInfos'] << entry
end def fetch_relative_value_of method: def fetch_relative_value_of(port, model)
port_formats = [port.sub('.', ':'), port.sub(':', '.')].uniq
interconnect_type = OneviewSDK::Interconnect.get_type(@client, model)
unless interconnect_type
list = OneviewSDK::Interconnect.get_types(@client).map { |t| t['name'] }
raise OneviewSDK::NotFound, "Interconnect type #{type} not found! Supported types: #{list}"
end
type_port = interconnect_type['portInfos'].find { |p| port_formats.include? p['portName'] }
raise OneviewSDK::NotFound, "Port #{port} not found" unless type_port
type_port['portNumber']
end I've done functionality tests with OneView 3.0 (20/40 F8 modules), OneView 3.0 Synergy edition (40Gb VC and 16Gb FC VC), even the multi-frame scenario (with 40Gb VC) is working fine. |
Nice! Can you submit a PR when you feel you're ready @vranystepan ? |
💯 ✨ Awesome job @vranystepan ! Waiting anxiously for the PR. 🎗️ Don't forget the unit tests update and to include issues #216 and #228 as solved in the CHANGELOG |
@fgbulsoni @jsmartt working on it. Do I have enough permissions in this repo? |
@vranystepan Can you try the
Since this is a bugfix/enhancement and I don't think we've added any other resource to be released, something like this should be good for the changelog: Unreleased ChangesSuggested release: v4.3.1Bug fixes & Enhancements: |
@fgbulsoni ahh, now I got your point :) I've raised a PR #230 |
merged. |
Scenario/Intent
Virtual Connect SE 40Gb F8 Module for Synergy
, oneview-sdk does not support this kind of uplink ports.Frame 1, ICM3, Q1
andFrame 2, ICM6, Q1
.LIGUplinkSet
does not support such featureEnvironment Details
Steps to Reproduce
Try to create
LIGUplinkSet
with following uplink ports:SDK will raise error since
API200::LIGUplinkSet
can't handle anything with Q prefix.theoretical analysis for Q ports
I've found that Q ports in
Virtual Connect SE 40Gb F8 Module for Synergy
have following convention for the relative numbering:This also means that we have to distinguish between QN and QN:M ports within the
relative_value_of
method. So we have to check whether Stringport
contains.
or:
delimiter.M
will be used as a addition to the base number which will be the same for variantsdirty draft (needs A LOT OF improvements :) ):
theoretical analysis for multiple synergy frames
I guess that we can edit
add_uplink
method inAPI200::LIGUplinkSet
this way:Open topics
Virtual Connect SE 16Gb FC Module for Synergy
module also has Q ports. Do these ports have the same offset?Update for
Virtual Connect SE 16Gb FC Module for Synergy
:Each FC module has 4x QSFP ports (these ports can be used with splitter only, so you can allocate QN:M ports only) and 8 SFP+ ports.
QSFP ports relative mapping:
SFP+ ports relative mapping:
This means that we also have to distinguish between ICM models;
Virtual Connect SE 16Gb FC Module for Synergy
andVirtual Connect SE 40Gb F8 Module for Synergy
... So maybe we'll override both relevant methodsadd_uplink
&relative_value_of
in API300::Synergy?The text was updated successfully, but these errors were encountered: