Can I remove the unique constrain for error "Asset/Device with such name already exists." - thingsboard

We are using open source Thingsboard for our IOT platform. One project has 100K devices/assets, and we have a tree structure for the assets/devices for example state -> county -> city, etc. Each county, we have an administrator who is responsible for asset/device creation. Frequently they use the same name for asset or device. Currently, Thingsboard doesn't allow duplicated name for asset/device. If we use the same name, we will get error messages
Asset with such name already exists
or
Device with such name already exists
We are thinking to remove this unique constrain but not sure if there is any side effect. Thanks.

It is not recommended to remove the unique constraint, but there may be workarounds:
Make the names unique, e.g. by concating the structure in the Tree for unique names (State_County_City_Device) or use the Device ID as name. In the Dashboards you can utilize the Label Field for a friendly-name.
See issue here: https://github.com/thingsboard/thingsboard/issues/4439

Related

Suitelink Reference Table

I work with Wonderware software. One of the objects used to perform communication between Wonderware and the PLC is called Suitelink. In it, I have a table defined that has the name of one of my application fields on the left side and the name of the PLC tag providing its value on the right.
Once this saved and activated (deployed) the PLC tags will feed values in the field attributes to Wonderware.
Does anyone know where is this list saved in the system?
I am working at a web page and want to retrieve this list dynamically so I can have the page updated based on the current live value of the PLC tag being used.
I have looked in the database but could not find it.
C:\ProgramData\Wonderware\DAServer
Then within there you'll have several subfolders for your DA Servers. Open the subfolder to find a *.AAcfg file and your contents are in there in what looks like an XML format. You'll be hunting for all the <DeviceItem> tags

CNContact unique id between devices

I'm having a bit of a problem with trying to access the same contact between multiple devices. My goal is to have a user select a contact and select a phone number and email address, which will then be stored in a database. If the user opens the app on another device, I would like to have the same contact selected.
I was hoping to use the CNContact.identifier for this case, but it appears that it is a device specific id. I could store the identifier for each device, but that would require the user matching contacts and that doesn't seam ideal.
This doesn't seam like it should be difficult but apparently I'm missing something. Thoughts?
The solution that seams to working for me is, I store the Contact identifiers, Address identifiers, Contact name, and the Address in my database. Then I take a mutli-step appoarch.
Search for Contact:
I attempt to find the contact based on the stored contact.identifiers I have already saved.
If I find 1 contact (identifier matched) => Great! I then attempt to match the found contact to my address.identifiers. Once again, if I find only 1 match, we're great! If not I then go to attempt to find an address (See below)
If I find no contacts (no identifiers matched) => I attempt to find the contact based on the Contact Name I had saved previously. If I do find a match, I then go to attempt to find the matching address (see below).
Search for Address:
Since at this point, I have a CNContact record that I believe matches, I look at each of their postalAddresses and compare it against the Street/city/state/zipcode/country that I have stored in my database.
If we find that perfect match, then I update my identifiers to include the new address/contact identifiers
If we ultimately don't find a match, I give the user an option to manually select the contact/address from their device.

How to get asnum and org values for the IP address with lua-geoip?

I am using the lua-geoip library.
How do I use "geoip asnum" and "geoip org" to get the asnum and org value from ipaddress using lua script?
If I understand correctly your question, you're looking to get an Autonomous System Number and ISP Organization for an IP address.
These values are stored in two databases: GeoIPASNum.dat and GeoIPOrg.dat. (Note that ASN number already contains an organization name, which may be sufficient for your purposes, for example: "AS15169 Google Inc.".)
At this moment the lua-geoip (v0.1.2) does not support either of these files.
You may add this support by cloning the country db, replacing country with asnum in the text.
https://github.com/agladysh/lua-geoip/blob/master/src/country.c
Then change query functions to use GeoIP_org_by_name instead of GeoIP_id_by_name — and push the result as a string, not country_info.
The process should be similar for the org DB should you need it.
See usage here:
https://github.com/maxmind/geoip-api-c/blob/master/test/test-geoip-asnum.c
https://github.com/maxmind/geoip-api-c/blob/master/test/test-geoip-org.c
(Full disclosure: I'm the maintainer of lua-geoip)

Accessing nested LDAP roles in Oracle Internet Directory (OID) within Grails and SpringSecurity

In our LDAP directory, we have users, who are mapped to groups. Those groups may be mapped to other groups. For example:
cn=group1,cn=groups,dc=example,dc=com
uniquemember cn=user1,cn=user,dc=example,dc=com
cn=group2,cn=groups,dc=example,dc=com
uniquemember cn=user2,cn=user,dc=example,dc=com
uniquemember cn=group1,cn=user,dc=example,dc=com
So User1 belongs to Group1, but User2 belongs to Group2, which in turn belongs to Group1
Within Grails, User1 has authority to Group1, but User2 only has authority to Group2. From what I've seen, there is no way to cause it to recursively look at the tree. Realistically, I probably only need a 2 level hierarchy, but even that doesn't seem to work.
I'm attempting to work through the Custom UserDetailsContextManager to see if I can iterate over the initial results and re-query LDAP by group, but I thought I'd see if there was an easier/better way.
You probably already saw this, but this is from the documentation:
// If you don't want to support group membership recursion (groups in groups), then use the following setting
// grails.plugins.springsecurity.ldap.authorities.groupSearchFilter = 'member={0}' // Active Directory specific
// If you wish to support groups with group as members (recursive groups), use the following
grails.plugins.springsecurity.ldap.authorities.groupSearchFilter = '(member:1.2.840.113556.1.4.1941:={0})' // Active Directory specific
http://grails-plugins.github.com/grails-spring-security-ldap/docs/manual/guide/2.%20Usage.html
Oracle OID has a product-specific extension for traversing the hierarchy, known as CONNECT_BY, which has LDAP OID 2.16.840.1.113894.1.8.3 . You can add this as a request control to ask the server to connect/follow hierarchies according to an attribute you specify. This can be done using both a Java LDAP client program, or using something like OpenLDAP ldapsearch, although the set-up is a little tricky.
If you want to use Java to follow the hierarchy, this page contains a sample program which shows how to setup the required javax.naming.ldap.Control implementation class, in this case named ConnectByControl.
You can also perform this sort of hierarchical search using ldapsearch, but it requires some preparation and implied understanding of the required control value, as the value is concatenated then base64-encoded. The value is in two-parts - the follow-me depth (0=unlimited), followed by the connect-by attribute name (in this case, uniquemember is the desired name). Set the baseDN in your query to the entry where you want to start the hierarchical search.
ldapsearch -H ldap://myoidserver.mycompany.com:389 -e 2.16.840.1.113894.1.8.3=MBECAQAEDHVuaXF1ZW1lbWJlcg== -b cn=some_group_containing_groups_nested_by_uniquemember,cn=some_groups,dc=mycompany,dc=com "(objectClass=*)" dn uniquemember
The -e 2.16.840.1.113894.1.8.3= adds the CONNECT_BY request control. The value, MBECAQAEDHVuaXF1ZW1lbWJlcg==, is ASN.1 BER-encoded then base64-encoded value 0uniquemember, for the depth and attribute-name mentioned above. This will print first the dn for cn=some_group_containing_groups_nested_by_uniquemember,... and its direct (user) uniquemembers, then each uniquemember will be "connected" or followed. If that entry itself has a set of uniquemember, i.e. it is a nested group, the process will continue until leaf/user entries are reached that have no nested uniquemembers.

Assigning email addresses to TFS users when not using AD [duplicate]

In my Team Foundation Server, I have a collection containing a Team Project. This Team Project has several contributors. The following lines of code get all contributors of that project:
TfsTeamProjectCollection collection = new TfsTeamProjectCollection(new Uri("http://tfs:8080/tfs/CollectionName"));
IGroupSecurityService groupSecurityService = collection.GetService<IGroupSecurityService>();
Identity contributors = groupSecurityService.ReadIdentity(SearchFactor.AccountName, "[ProjectName]\\Contributors", QueryMembership.Expanded);
Identity[] members = groupSecurityService.ReadIdentities(SearchFactor.Sid, contributors.Members, QueryMembership.None);
Each Identity in members has a Property MailAddress, which in my case is equal to string.Empty.
Where do I administrate those mail addresses?
My first idea was to have a look at the users in Start->Administrative Tools->Computer Management->Users
I selected one of the users and opened his properties. I thought there might be an email property that the TFS would take. But I couldn't find one.
Then I opened the TFS Administration Console, looked for Group Membership and navigated to one of the users. There is also no way of editing properties.
Does anyone know where to set that email address?
Great question! There is a TFS job that is scheduled to run every hour to update information about security identities stored in TFS against the details in Active Directory. Some of this information includes the display name, security identifier (SID), AD distinguished name, and e-mail address, among other details. You can find out this cache of details by looking at the tbl_security_identity_cache table in the configuration database.
Warning: Querying against or changing the database puts you in a position where you will likely not be able to get support from Microsoft. It's advised that you don't do this unless instructed by a Microsoft support representative in the context of an active support case. You were actually doing it right by using the TFS SDK to get this information.
If your TFS environment is not in an Active Directory environment, then it will attempt to synchronize information from the local machine where TFS is running. It won't have details about the e-mail address to use so it will be left blank.
Starting in the next version of TFS after TFS 2010, each user will be able to update their notification e-mail address in their profile using Team Web Access.
The following is for TFS 2013 Update 5
** WARNING ** Getting caught editing the TFS database directly
** will void your Microsoft Support Agreement. **
What follows is not for the uninitiated. ** Proceed at your own risk. **
Locate the user or users with email addresses needing to be set. There can be duplicates in the Identities table. I found that the ones with the highest SequenceId were the active Identities.
Use Tfs_TFSConfiguration
SELECT i1.AccountName, i1.Id FROM tbl_Identity AS i1
LEFT OUTER JOIN tbl_Identity AS i2
ON (i1.AccountName=i2.AccountName AND i1.SequenceId<i2.SequenceId)
WHERE i2.AccountName IS NULL
AND i1.AccountName in ('<your first user>','<another user>','<and so on>')
This gives a list of the most recent the Id(s), in GUID form, for the accounts that you need to update. These GUIDs must be reformatted into ArtifactId(s), which is a transformed binary format. This is accomplished by reversing the byte order (low to high) or each of the first three parts of the GUID, but leaving the last two parts in order. E.g.:
Returned 'Id' GUID =01020304-0506-0708-090A-0B0C0D0E0F10
Byte Swapped GUID =04030201-0605-0807-090A-0B0C0D0E0F10
Reformatted 'ArtifacId'=0x0403020106050807090A0B0C0D0E0F10
Next, you have to find the PropertyId(s) used by TFS for email notifications. In TFS 2013 U5, this can be found with the following query:
USE Tfs_TFSConfiguration
SELECT Name, PropertyId FROM tbl_PropertyDefinition WHERE Name LIKE '%Address%'
This will give you the PropertyId(s) for ConfirmedNotificationAddress and CustomNotificationAddresses; which are the two property fields used by TFS 2013 U5 to send notification emails.
Next, you have to find the InternalKindId for the Identity Framework for the TFS DatabaseCategory
USE Tfs_TFSConfiguration
SELECT Description, InternalKindId FROM tbl_PropertyArtifactKind
WHERE Description='Identity'
Now to put it all together, ...
If the configuration records for your user(s) already exist, you can update the settings with:
USE Tfs_TFSConfiguration
UPDATE tbl_PropertyValue SET LeadingStringValue='<user's notification email address>'
WHERE ArtifactId=<ArtifactId, reformatted from tbl_Identity query>
AND PropertyId IN ('<first PropertyId from tbl_PropertyDefinition>', '<second id>')
Note: that ArtifactId is a binary value, based upon a semi-byte-swapped database GUID, and will not match a quoted value in the UPDATE query. I.e. this part of the query will look something like:
WHERE ArtifactId=0x90D490F6BF7B31491CB894323F38A91F AND
Below I assume that the PartitionId is '1'; this should be verified before you continue by a brief scan of the records in the tbl_PropertyValue table.
If you are loading configuration settings that have not yet been set:
USE Tfs_TFSConfiguration
INSERT INTO tbl_PropertyValue
(PartitionId, ArtifactId, InternalKindId, Version, PropertyId, LeadingStringValue)
VALUES ('1', <ArtifactId, reformatted from tbl_Identity query>,
'<InternalKindId from tbl_PropertyArtifactKind>',
'0',
'<first PropertyId from tbl_PropertyDefinition>',
'<user's notification email address>'),
('1', <ArtifactId, reformatted from tbl_Identity query>,
'<InternalKindId from tbl_PropertyArtifactKind>',
'0',
'<second PropertyId from tbl_PropertyDefinition>',
'<user's notification email address>')
Note: that ArtifactId must be an unquoted binary value, transformed from the GUID returned from the tbl_Identity as explained above.
Note: that two records are created for each ArtifactId, one for each PropertyId.
** WARNING ** Getting caught editing the TFS database directly
** will void your Microsoft Support Agreement. **
** Proceed at your own risk. **
(This works for me, ... but, I do not have a Microsoft Support Agreement to invalidate.)
If Active Directory does not get synched with TFS, and assuming your goal to keep email address is for sending notifications you can use the IEventService.GetEventSubscriptions() methods.
var eventService = (IEventService)collection.GetService(typeof(IEventService));
foreach (var member in members)
{
var subscription = eventService.GetEventSubscriptions(member.DisplayName).First();
{
if (subscription != null && string.IsNullOrEmpty(member.MailAddress))
member.MailAddress = subscription.DeliveryPreference.Address;
}
}
I believe this is kept in Active Directory.
For TFS2017+, each user can have a preferred email address, that they can setup in their profile, on the web interface.
It can override, or replace the email set in Active Directory. It also has the benefit to be an instant change, no synchronisation needed.
The field will be initialized with the value that has been set in Active Directory. The synchronization doesn't seem to happen anymore.

Resources