series-demystifying-icontrol-rest

8 Topics
"}},"componentScriptGroups({\"componentId\":\"custom.widget.Beta_MetaNav\"})":{"__typename":"ComponentScriptGroups","scriptGroups":{"__typename":"ComponentScriptGroupsDefinition","afterInteractive":{"__typename":"PageScriptGroupDefinition","group":"AFTER_INTERACTIVE","scriptIds":[]},"lazyOnLoad":{"__typename":"PageScriptGroupDefinition","group":"LAZY_ON_LOAD","scriptIds":[]}},"componentScripts":[]},"component({\"componentId\":\"custom.widget.Beta_Footer\"})":{"__typename":"Component","render({\"context\":{\"component\":{\"entities\":[],\"props\":{}},\"page\":{\"entities\":[],\"name\":\"TagPage\",\"props\":{},\"url\":\"https://community.f5.com/tag/series-demystifying-icontrol-rest\"}}})":{"__typename":"ComponentRenderResult","html":"
 
 
 
 
 

\"F5 ©2024 F5, Inc. All rights reserved.
Trademarks Policies Privacy California Privacy Do Not Sell My Personal Information
"}},"componentScriptGroups({\"componentId\":\"custom.widget.Beta_Footer\"})":{"__typename":"ComponentScriptGroups","scriptGroups":{"__typename":"ComponentScriptGroupsDefinition","afterInteractive":{"__typename":"PageScriptGroupDefinition","group":"AFTER_INTERACTIVE","scriptIds":[]},"lazyOnLoad":{"__typename":"PageScriptGroupDefinition","group":"LAZY_ON_LOAD","scriptIds":[]}},"componentScripts":[]},"component({\"componentId\":\"custom.widget.Tag_Manager_Helper\"})":{"__typename":"Component","render({\"context\":{\"component\":{\"entities\":[],\"props\":{}},\"page\":{\"entities\":[],\"name\":\"TagPage\",\"props\":{},\"url\":\"https://community.f5.com/tag/series-demystifying-icontrol-rest\"}}})":{"__typename":"ComponentRenderResult","html":" "}},"componentScriptGroups({\"componentId\":\"custom.widget.Tag_Manager_Helper\"})":{"__typename":"ComponentScriptGroups","scriptGroups":{"__typename":"ComponentScriptGroupsDefinition","afterInteractive":{"__typename":"PageScriptGroupDefinition","group":"AFTER_INTERACTIVE","scriptIds":[]},"lazyOnLoad":{"__typename":"PageScriptGroupDefinition","group":"LAZY_ON_LOAD","scriptIds":[]}},"componentScripts":[]},"component({\"componentId\":\"custom.widget.Consent_Blackbar\"})":{"__typename":"Component","render({\"context\":{\"component\":{\"entities\":[],\"props\":{}},\"page\":{\"entities\":[],\"name\":\"TagPage\",\"props\":{},\"url\":\"https://community.f5.com/tag/series-demystifying-icontrol-rest\"}}})":{"__typename":"ComponentRenderResult","html":"
"}},"componentScriptGroups({\"componentId\":\"custom.widget.Consent_Blackbar\"})":{"__typename":"ComponentScriptGroups","scriptGroups":{"__typename":"ComponentScriptGroupsDefinition","afterInteractive":{"__typename":"PageScriptGroupDefinition","group":"AFTER_INTERACTIVE","scriptIds":[]},"lazyOnLoad":{"__typename":"PageScriptGroupDefinition","group":"LAZY_ON_LOAD","scriptIds":[]}},"componentScripts":[]},"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/community/NavbarDropdownToggle\"]})":[{"__ref":"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/common/OverflowNav\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/common/OverflowNav-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageView/MessageViewInline\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageView/MessageViewInline-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/customComponent/CustomComponent\"]})":[{"__ref":"CachedAsset:text:en_US-components/customComponent/CustomComponent-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/users/UserLink\"]})":[{"__ref":"CachedAsset:text:en_US-components/users/UserLink-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageSubject\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageSubject-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageBody\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageBody-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageTime\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageTime-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/nodes/NodeIcon\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/nodes/NodeIcon-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageUnreadCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageUnreadCount-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageViewCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageViewCount-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/kudos/KudosCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/kudos/KudosCount-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageRepliesCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageRepliesCount-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/users/UserAvatar\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/users/UserAvatar-1740415735000"}]},"CachedAsset:pages-1742463843167":{"__typename":"CachedAsset","id":"pages-1742463843167","value":[{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"HowDoI.GetInvolved.MvpProgram","type":"COMMUNITY","urlPath":"/c/how-do-i/get-involved/mvp-program","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"BlogViewAllPostsPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId/all-posts/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"CasePortalPage","type":"CASE_PORTAL","urlPath":"/caseportal","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"CreateGroupHubPage","type":"GROUP_HUB","urlPath":"/groups/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"CaseViewPage","type":"CASE_DETAILS","urlPath":"/case/:caseId/:caseNumber","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"InboxPage","type":"COMMUNITY","urlPath":"/inbox","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"HowDoI.GetInvolved.AdvocacyProgram","type":"COMMUNITY","urlPath":"/c/how-do-i/get-involved/advocacy-program","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"HowDoI.GetHelp.NonCustomer","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help/non-customer","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"HelpFAQPage","type":"COMMUNITY","urlPath":"/help","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"HowDoI.GetHelp.F5Customer","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help/f5-customer","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"IdeaMessagePage","type":"IDEA_POST","urlPath":"/idea/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"IdeaViewAllIdeasPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/all-ideas/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"LoginPage","type":"USER","urlPath":"/signin","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"BlogPostPage","type":"BLOG","urlPath":"/category/:categoryId/blogs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"HowDoI.GetInvolved","type":"COMMUNITY","urlPath":"/c/how-do-i/get-involved","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"HowDoI.Learn","type":"COMMUNITY","urlPath":"/c/how-do-i/learn","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1739501996000,"localOverride":null,"page":{"id":"Test","type":"CUSTOM","urlPath":"/custom-test-2","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"ThemeEditorPage","type":"COMMUNITY","urlPath":"/designer/themes","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"TkbViewAllArticlesPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId/all-articles/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"OccasionEditPage","type":"EVENT","urlPath":"/event/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"OAuthAuthorizationAllowPage","type":"USER","urlPath":"/auth/authorize/allow","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"PageEditorPage","type":"COMMUNITY","urlPath":"/designer/pages","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"PostPage","type":"COMMUNITY","urlPath":"/category/:categoryId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"ForumBoardPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"TkbBoardPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"EventPostPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"UserBadgesPage","type":"COMMUNITY","urlPath":"/users/:login/:userId/badges","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"GroupHubMembershipAction","type":"GROUP_HUB","urlPath":"/membership/join/:nodeId/:membershipType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"MaintenancePage","type":"COMMUNITY","urlPath":"/maintenance","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"IdeaReplyPage","type":"IDEA_REPLY","urlPath":"/idea/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"UserSettingsPage","type":"USER","urlPath":"/mysettings/:userSettingsTab","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"GroupHubsPage","type":"GROUP_HUB","urlPath":"/groups","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"ForumPostPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"OccasionRsvpActionPage","type":"OCCASION","urlPath":"/event/:boardId/:messageSubject/:messageId/rsvp/:responseType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"VerifyUserEmailPage","type":"USER","urlPath":"/verifyemail/:userId/:verifyEmailToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"AllOccasionsPage","type":"OCCASION","urlPath":"/category/:categoryId/events/:boardId/all-events/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"EventBoardPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"TkbReplyPage","type":"TKB_REPLY","urlPath":"/kb/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"IdeaBoardPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"CommunityGuideLinesPage","type":"COMMUNITY","urlPath":"/communityguidelines","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"CaseCreatePage","type":"SALESFORCE_CASE_CREATION","urlPath":"/caseportal/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"TkbEditPage","type":"TKB","urlPath":"/kb/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"ForgotPasswordPage","type":"USER","urlPath":"/forgotpassword","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"IdeaEditPage","type":"IDEA","urlPath":"/idea/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"TagPage","type":"COMMUNITY","urlPath":"/tag/:tagName","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"BlogBoardPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"OccasionMessagePage","type":"OCCASION_TOPIC","urlPath":"/event/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"ManageContentPage","type":"COMMUNITY","urlPath":"/managecontent","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"ClosedMembershipNodeNonMembersPage","type":"GROUP_HUB","urlPath":"/closedgroup/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"HowDoI.GetHelp.Community","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help/community","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"CommunityPage","type":"COMMUNITY","urlPath":"/","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"HowDoI.GetInvolved.ContributeCode","type":"COMMUNITY","urlPath":"/c/how-do-i/get-involved/contribute-code","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"ForumMessagePage","type":"FORUM_TOPIC","urlPath":"/discussions/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"IdeaPostPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"BlogMessagePage","type":"BLOG_ARTICLE","urlPath":"/blog/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"RegistrationPage","type":"USER","urlPath":"/register","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"EditGroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"ForumEditPage","type":"FORUM","urlPath":"/discussions/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"ResetPasswordPage","type":"USER","urlPath":"/resetpassword/:userId/:resetPasswordToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"TkbMessagePage","type":"TKB_ARTICLE","urlPath":"/kb/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"HowDoI.Learn.AboutIrules","type":"COMMUNITY","urlPath":"/c/how-do-i/learn/about-irules","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"BlogEditPage","type":"BLOG","urlPath":"/blog/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"HowDoI.GetHelp.F5Support","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help/f5-support","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"ManageUsersPage","type":"USER","urlPath":"/users/manage/:tab?/:manageUsersTab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"ForumReplyPage","type":"FORUM_REPLY","urlPath":"/discussions/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"PrivacyPolicyPage","type":"COMMUNITY","urlPath":"/privacypolicy","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"NotificationPage","type":"COMMUNITY","urlPath":"/notifications","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"UserPage","type":"USER","urlPath":"/users/:login/:userId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"HealthCheckPage","type":"COMMUNITY","urlPath":"/health","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"OccasionReplyPage","type":"OCCASION_REPLY","urlPath":"/event/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"ManageMembersPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/manage/:tab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"SearchResultsPage","type":"COMMUNITY","urlPath":"/search","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"BlogReplyPage","type":"BLOG_REPLY","urlPath":"/blog/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"GroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"TermsOfServicePage","type":"COMMUNITY","urlPath":"/termsofservice","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"HowDoI.GetHelp","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"HowDoI.GetHelp.SecurityIncident","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help/security-incident","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"CategoryPage","type":"CATEGORY","urlPath":"/category/:categoryId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"ForumViewAllTopicsPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/all-topics/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"TkbPostPage","type":"TKB","urlPath":"/category/:categoryId/kbs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"GroupHubPostPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742463843167,"localOverride":null,"page":{"id":"HowDoI","type":"COMMUNITY","urlPath":"/c/how-do-i","__typename":"PageDescriptor"},"__typename":"PageResource"}],"localOverride":false},"CachedAsset:text:en_US-components/context/AppContext/AppContextProvider-0":{"__typename":"CachedAsset","id":"text:en_US-components/context/AppContext/AppContextProvider-0","value":{"noCommunity":"Cannot find community","noUser":"Cannot find current user","noNode":"Cannot find node with id {nodeId}","noMessage":"Cannot find message with id {messageId}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Loading/LoadingDot-0":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Loading/LoadingDot-0","value":{"title":"Loading..."},"localOverride":false},"User:user:-1":{"__typename":"User","id":"user:-1","uid":-1,"login":"Former Member","email":"","avatar":null,"rank":null,"kudosWeight":1,"registrationData":{"__typename":"RegistrationData","status":"ANONYMOUS","registrationTime":null,"confirmEmailStatus":false,"registrationAccessLevel":"VIEW","ssoRegistrationFields":[]},"ssoId":null,"profileSettings":{"__typename":"ProfileSettings","dateDisplayStyle":{"__typename":"InheritableStringSettingWithPossibleValues","key":"layout.friendly_dates_enabled","value":"false","localValue":"true","possibleValues":["true","false"]},"dateDisplayFormat":{"__typename":"InheritableStringSetting","key":"layout.format_pattern_date","value":"dd-MMM-yyyy","localValue":"MM-dd-yyyy"},"language":{"__typename":"InheritableStringSettingWithPossibleValues","key":"profile.language","value":"en-US","localValue":null,"possibleValues":["en-US"]}},"deleted":false},"Theme:customTheme1":{"__typename":"Theme","id":"customTheme1"},"CachedAsset:theme:customTheme1-1742463842725":{"__typename":"CachedAsset","id":"theme:customTheme1-1742463842725","value":{"id":"customTheme1","animation":{"fast":"150ms","normal":"250ms","slow":"500ms","slowest":"750ms","function":"cubic-bezier(0.07, 0.91, 0.51, 1)","__typename":"AnimationThemeSettings"},"avatar":{"borderRadius":"50%","collections":["custom"],"__typename":"AvatarThemeSettings"},"basics":{"browserIcon":{"imageAssetName":"JimmyPackets-512-1702592938213.png","imageLastModified":"1702592945815","__typename":"ThemeAsset"},"customerLogo":{"imageAssetName":"f5_logo_fix-1704824537976.svg","imageLastModified":"1704824540697","__typename":"ThemeAsset"},"maximumWidthOfPageContent":"1600px","oneColumnNarrowWidth":"800px","gridGutterWidthMd":"30px","gridGutterWidthXs":"10px","pageWidthStyle":"WIDTH_OF_PAGE_CONTENT","__typename":"BasicsThemeSettings"},"buttons":{"borderRadiusSm":"5px","borderRadius":"5px","borderRadiusLg":"5px","paddingY":"5px","paddingYLg":"7px","paddingYHero":"var(--lia-bs-btn-padding-y-lg)","paddingX":"12px","paddingXLg":"14px","paddingXHero":"42px","fontStyle":"NORMAL","fontWeight":"400","textTransform":"NONE","disabledOpacity":0.5,"primaryTextColor":"var(--lia-bs-white)","primaryTextHoverColor":"var(--lia-bs-white)","primaryTextActiveColor":"var(--lia-bs-white)","primaryBgColor":"var(--lia-bs-primary)","primaryBgHoverColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) * 0.85))","primaryBgActiveColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) * 0.7))","primaryBorder":"1px solid transparent","primaryBorderHover":"1px solid transparent","primaryBorderActive":"1px solid transparent","primaryBorderFocus":"1px solid var(--lia-bs-white)","primaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","secondaryTextColor":"var(--lia-bs-gray-900)","secondaryTextHoverColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.95))","secondaryTextActiveColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.9))","secondaryBgColor":"var(--lia-bs-gray-400)","secondaryBgHoverColor":"hsl(var(--lia-bs-gray-400-h), var(--lia-bs-gray-400-s), calc(var(--lia-bs-gray-400-l) * 0.96))","secondaryBgActiveColor":"hsl(var(--lia-bs-gray-400-h), var(--lia-bs-gray-400-s), calc(var(--lia-bs-gray-400-l) * 0.92))","secondaryBorder":"1px solid transparent","secondaryBorderHover":"1px solid transparent","secondaryBorderActive":"1px solid transparent","secondaryBorderFocus":"1px solid transparent","secondaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","tertiaryTextColor":"var(--lia-bs-gray-900)","tertiaryTextHoverColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.95))","tertiaryTextActiveColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.9))","tertiaryBgColor":"transparent","tertiaryBgHoverColor":"transparent","tertiaryBgActiveColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.04)","tertiaryBorder":"1px solid transparent","tertiaryBorderHover":"1px solid hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","tertiaryBorderActive":"1px solid transparent","tertiaryBorderFocus":"1px solid transparent","tertiaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","destructiveTextColor":"var(--lia-bs-danger)","destructiveTextHoverColor":"hsl(var(--lia-bs-danger-h), var(--lia-bs-danger-s), calc(var(--lia-bs-danger-l) * 0.95))","destructiveTextActiveColor":"hsl(var(--lia-bs-danger-h), var(--lia-bs-danger-s), calc(var(--lia-bs-danger-l) * 0.9))","destructiveBgColor":"var(--lia-bs-gray-300)","destructiveBgHoverColor":"hsl(var(--lia-bs-gray-300-h), var(--lia-bs-gray-300-s), calc(var(--lia-bs-gray-300-l) * 0.96))","destructiveBgActiveColor":"hsl(var(--lia-bs-gray-300-h), var(--lia-bs-gray-300-s), calc(var(--lia-bs-gray-300-l) * 0.92))","destructiveBorder":"1px solid transparent","destructiveBorderHover":"1px solid transparent","destructiveBorderActive":"1px solid transparent","destructiveBorderFocus":"1px solid transparent","destructiveBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","__typename":"ButtonsThemeSettings"},"border":{"color":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","mainContent":"NONE","sideContent":"NONE","radiusSm":"3px","radius":"5px","radiusLg":"9px","radius50":"100vw","__typename":"BorderThemeSettings"},"boxShadow":{"xs":"0 0 0 1px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.08), 0 3px 0 -1px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.08)","sm":"0 2px 4px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.06)","md":"0 5px 15px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.15)","lg":"0 10px 30px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.15)","__typename":"BoxShadowThemeSettings"},"cards":{"bgColor":"var(--lia-panel-bg-color)","borderRadius":"var(--lia-panel-border-radius)","boxShadow":"var(--lia-box-shadow-xs)","__typename":"CardsThemeSettings"},"chip":{"maxWidth":"300px","height":"30px","__typename":"ChipThemeSettings"},"coreTypes":{"defaultMessageLinkColor":"var(--lia-bs-primary)","defaultMessageLinkDecoration":"none","defaultMessageLinkFontStyle":"NORMAL","defaultMessageLinkFontWeight":"400","defaultMessageFontStyle":"NORMAL","defaultMessageFontWeight":"400","forumColor":"#0C5C8D","forumFontFamily":"var(--lia-bs-font-family-base)","forumFontWeight":"var(--lia-default-message-font-weight)","forumLineHeight":"var(--lia-bs-line-height-base)","forumFontStyle":"var(--lia-default-message-font-style)","forumMessageLinkColor":"var(--lia-default-message-link-color)","forumMessageLinkDecoration":"var(--lia-default-message-link-decoration)","forumMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","forumMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","forumSolvedColor":"#62C026","blogColor":"#730015","blogFontFamily":"var(--lia-bs-font-family-base)","blogFontWeight":"var(--lia-default-message-font-weight)","blogLineHeight":"1.75","blogFontStyle":"var(--lia-default-message-font-style)","blogMessageLinkColor":"var(--lia-default-message-link-color)","blogMessageLinkDecoration":"var(--lia-default-message-link-decoration)","blogMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","blogMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","tkbColor":"#C20025","tkbFontFamily":"var(--lia-bs-font-family-base)","tkbFontWeight":"var(--lia-default-message-font-weight)","tkbLineHeight":"1.75","tkbFontStyle":"var(--lia-default-message-font-style)","tkbMessageLinkColor":"var(--lia-default-message-link-color)","tkbMessageLinkDecoration":"var(--lia-default-message-link-decoration)","tkbMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","tkbMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","qandaColor":"#4099E2","qandaFontFamily":"var(--lia-bs-font-family-base)","qandaFontWeight":"var(--lia-default-message-font-weight)","qandaLineHeight":"var(--lia-bs-line-height-base)","qandaFontStyle":"var(--lia-default-message-link-font-style)","qandaMessageLinkColor":"var(--lia-default-message-link-color)","qandaMessageLinkDecoration":"var(--lia-default-message-link-decoration)","qandaMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","qandaMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","qandaSolvedColor":"#3FA023","ideaColor":"#F3704B","ideaFontFamily":"var(--lia-bs-font-family-base)","ideaFontWeight":"var(--lia-default-message-font-weight)","ideaLineHeight":"var(--lia-bs-line-height-base)","ideaFontStyle":"var(--lia-default-message-font-style)","ideaMessageLinkColor":"var(--lia-default-message-link-color)","ideaMessageLinkDecoration":"var(--lia-default-message-link-decoration)","ideaMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","ideaMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","contestColor":"#FCC845","contestFontFamily":"var(--lia-bs-font-family-base)","contestFontWeight":"var(--lia-default-message-font-weight)","contestLineHeight":"var(--lia-bs-line-height-base)","contestFontStyle":"var(--lia-default-message-link-font-style)","contestMessageLinkColor":"var(--lia-default-message-link-color)","contestMessageLinkDecoration":"var(--lia-default-message-link-decoration)","contestMessageLinkFontStyle":"ITALIC","contestMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","occasionColor":"#EE4B5B","occasionFontFamily":"var(--lia-bs-font-family-base)","occasionFontWeight":"var(--lia-default-message-font-weight)","occasionLineHeight":"var(--lia-bs-line-height-base)","occasionFontStyle":"var(--lia-default-message-font-style)","occasionMessageLinkColor":"var(--lia-default-message-link-color)","occasionMessageLinkDecoration":"var(--lia-default-message-link-decoration)","occasionMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","occasionMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","grouphubColor":"#491B62","categoryColor":"#949494","communityColor":"#FFFFFF","productColor":"#949494","__typename":"CoreTypesThemeSettings"},"colors":{"black":"#000000","white":"#FFFFFF","gray100":"#F7F7F7","gray200":"#F7F7F7","gray300":"#E8E8E8","gray400":"#D9D9D9","gray500":"#CCCCCC","gray600":"#949494","gray700":"#707070","gray800":"#545454","gray900":"#333333","dark":"#545454","light":"#F7F7F7","primary":"#0C5C8D","secondary":"#333333","bodyText":"#222222","bodyBg":"#F5F5F5","info":"#1D9CD3","success":"#62C026","warning":"#FFD651","danger":"#C20025","alertSystem":"#FF6600","textMuted":"#707070","highlight":"#FFFCAD","outline":"var(--lia-bs-primary)","custom":["#C20025","#081B85","#009639","#B3C6D7","#7CC0EB","#F29A36"],"__typename":"ColorsThemeSettings"},"divider":{"size":"3px","marginLeft":"4px","marginRight":"4px","borderRadius":"50%","bgColor":"var(--lia-bs-gray-600)","bgColorActive":"var(--lia-bs-gray-600)","__typename":"DividerThemeSettings"},"dropdown":{"fontSize":"var(--lia-bs-font-size-sm)","borderColor":"var(--lia-bs-border-color)","borderRadius":"var(--lia-bs-border-radius-sm)","dividerBg":"var(--lia-bs-gray-300)","itemPaddingY":"5px","itemPaddingX":"20px","headerColor":"var(--lia-bs-gray-700)","__typename":"DropdownThemeSettings"},"email":{"link":{"color":"#0069D4","hoverColor":"#0061c2","decoration":"none","hoverDecoration":"underline","__typename":"EmailLinkSettings"},"border":{"color":"#e4e4e4","__typename":"EmailBorderSettings"},"buttons":{"borderRadiusLg":"5px","paddingXLg":"16px","paddingYLg":"7px","fontWeight":"700","primaryTextColor":"#ffffff","primaryTextHoverColor":"#ffffff","primaryBgColor":"#0069D4","primaryBgHoverColor":"#005cb8","primaryBorder":"1px solid transparent","primaryBorderHover":"1px solid transparent","__typename":"EmailButtonsSettings"},"panel":{"borderRadius":"5px","borderColor":"#e4e4e4","__typename":"EmailPanelSettings"},"__typename":"EmailThemeSettings"},"emoji":{"skinToneDefault":"#ffcd43","skinToneLight":"#fae3c5","skinToneMediumLight":"#e2cfa5","skinToneMedium":"#daa478","skinToneMediumDark":"#a78058","skinToneDark":"#5e4d43","__typename":"EmojiThemeSettings"},"heading":{"color":"var(--lia-bs-body-color)","fontFamily":"Inter","fontStyle":"NORMAL","fontWeight":"600","h1FontSize":"30px","h2FontSize":"25px","h3FontSize":"20px","h4FontSize":"18px","h5FontSize":"16px","h6FontSize":"16px","lineHeight":"1.2","subHeaderFontSize":"11px","subHeaderFontWeight":"500","h1LetterSpacing":"normal","h2LetterSpacing":"normal","h3LetterSpacing":"normal","h4LetterSpacing":"normal","h5LetterSpacing":"normal","h6LetterSpacing":"normal","subHeaderLetterSpacing":"2px","h1FontWeight":"var(--lia-bs-headings-font-weight)","h2FontWeight":"var(--lia-bs-headings-font-weight)","h3FontWeight":"var(--lia-bs-headings-font-weight)","h4FontWeight":"var(--lia-bs-headings-font-weight)","h5FontWeight":"var(--lia-bs-headings-font-weight)","h6FontWeight":"var(--lia-bs-headings-font-weight)","__typename":"HeadingThemeSettings"},"icons":{"size10":"10px","size12":"12px","size14":"14px","size16":"16px","size20":"20px","size24":"24px","size30":"30px","size40":"40px","size50":"50px","size60":"60px","size80":"80px","size120":"120px","size160":"160px","__typename":"IconsThemeSettings"},"imagePreview":{"bgColor":"var(--lia-bs-gray-900)","titleColor":"var(--lia-bs-white)","controlColor":"var(--lia-bs-white)","controlBgColor":"var(--lia-bs-gray-800)","__typename":"ImagePreviewThemeSettings"},"input":{"borderColor":"var(--lia-bs-gray-600)","disabledColor":"var(--lia-bs-gray-600)","focusBorderColor":"var(--lia-bs-primary)","labelMarginBottom":"10px","btnFontSize":"var(--lia-bs-font-size-sm)","focusBoxShadow":"0 0 0 3px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","checkLabelMarginBottom":"2px","checkboxBorderRadius":"3px","borderRadiusSm":"var(--lia-bs-border-radius-sm)","borderRadius":"var(--lia-bs-border-radius)","borderRadiusLg":"var(--lia-bs-border-radius-lg)","formTextMarginTop":"4px","textAreaBorderRadius":"var(--lia-bs-border-radius)","activeFillColor":"var(--lia-bs-primary)","__typename":"InputThemeSettings"},"loading":{"dotDarkColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.2)","dotLightColor":"hsla(var(--lia-bs-white-h), var(--lia-bs-white-s), var(--lia-bs-white-l), 0.5)","barDarkColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.06)","barLightColor":"hsla(var(--lia-bs-white-h), var(--lia-bs-white-s), var(--lia-bs-white-l), 0.4)","__typename":"LoadingThemeSettings"},"link":{"color":"var(--lia-bs-primary)","hoverColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) - 10%))","decoration":"none","hoverDecoration":"underline","__typename":"LinkThemeSettings"},"listGroup":{"itemPaddingY":"15px","itemPaddingX":"15px","borderColor":"var(--lia-bs-gray-300)","__typename":"ListGroupThemeSettings"},"modal":{"contentTextColor":"var(--lia-bs-body-color)","contentBg":"var(--lia-bs-white)","backgroundBg":"var(--lia-bs-black)","smSize":"440px","mdSize":"760px","lgSize":"1080px","backdropOpacity":0.3,"contentBoxShadowXs":"var(--lia-bs-box-shadow-sm)","contentBoxShadow":"var(--lia-bs-box-shadow)","headerFontWeight":"700","__typename":"ModalThemeSettings"},"navbar":{"position":"FIXED","background":{"attachment":null,"clip":null,"color":"var(--lia-bs-white)","imageAssetName":null,"imageLastModified":"0","origin":null,"position":"CENTER_CENTER","repeat":"NO_REPEAT","size":"COVER","__typename":"BackgroundProps"},"backgroundOpacity":0.8,"paddingTop":"15px","paddingBottom":"15px","borderBottom":"1px solid var(--lia-bs-border-color)","boxShadow":"var(--lia-bs-box-shadow-sm)","brandMarginRight":"30px","brandMarginRightSm":"10px","brandLogoHeight":"30px","linkGap":"10px","linkJustifyContent":"flex-start","linkPaddingY":"5px","linkPaddingX":"10px","linkDropdownPaddingY":"9px","linkDropdownPaddingX":"var(--lia-nav-link-px)","linkColor":"var(--lia-bs-body-color)","linkHoverColor":"var(--lia-bs-primary)","linkFontSize":"var(--lia-bs-font-size-sm)","linkFontStyle":"NORMAL","linkFontWeight":"400","linkTextTransform":"NONE","linkLetterSpacing":"normal","linkBorderRadius":"var(--lia-bs-border-radius-sm)","linkBgColor":"transparent","linkBgHoverColor":"transparent","linkBorder":"none","linkBorderHover":"none","linkBoxShadow":"none","linkBoxShadowHover":"none","linkTextBorderBottom":"none","linkTextBorderBottomHover":"none","dropdownPaddingTop":"10px","dropdownPaddingBottom":"15px","dropdownPaddingX":"10px","dropdownMenuOffset":"2px","dropdownDividerMarginTop":"10px","dropdownDividerMarginBottom":"10px","dropdownBorderColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","controllerBgHoverColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.1)","controllerIconColor":"var(--lia-bs-body-color)","controllerIconHoverColor":"var(--lia-bs-body-color)","controllerTextColor":"var(--lia-nav-controller-icon-color)","controllerTextHoverColor":"var(--lia-nav-controller-icon-hover-color)","controllerHighlightColor":"hsla(30, 100%, 50%)","controllerHighlightTextColor":"var(--lia-yiq-light)","controllerBorderRadius":"var(--lia-border-radius-50)","hamburgerColor":"var(--lia-nav-controller-icon-color)","hamburgerHoverColor":"var(--lia-nav-controller-icon-color)","hamburgerBgColor":"transparent","hamburgerBgHoverColor":"transparent","hamburgerBorder":"none","hamburgerBorderHover":"none","collapseMenuMarginLeft":"20px","collapseMenuDividerBg":"var(--lia-nav-link-color)","collapseMenuDividerOpacity":0.16,"__typename":"NavbarThemeSettings"},"pager":{"textColor":"var(--lia-bs-link-color)","textFontWeight":"var(--lia-font-weight-md)","textFontSize":"var(--lia-bs-font-size-sm)","__typename":"PagerThemeSettings"},"panel":{"bgColor":"var(--lia-bs-white)","borderRadius":"var(--lia-bs-border-radius)","borderColor":"var(--lia-bs-border-color)","boxShadow":"none","__typename":"PanelThemeSettings"},"popover":{"arrowHeight":"8px","arrowWidth":"16px","maxWidth":"300px","minWidth":"100px","headerBg":"var(--lia-bs-white)","borderColor":"var(--lia-bs-border-color)","borderRadius":"var(--lia-bs-border-radius)","boxShadow":"0 0.5rem 1rem hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.15)","__typename":"PopoverThemeSettings"},"prism":{"color":"#000000","bgColor":"#f5f2f0","fontFamily":"var(--font-family-monospace)","fontSize":"var(--lia-bs-font-size-base)","fontWeightBold":"var(--lia-bs-font-weight-bold)","fontStyleItalic":"italic","tabSize":2,"highlightColor":"#b3d4fc","commentColor":"#62707e","punctuationColor":"#6f6f6f","namespaceOpacity":"0.7","propColor":"#990055","selectorColor":"#517a00","operatorColor":"#906736","operatorBgColor":"hsla(0, 0%, 100%, 0.5)","keywordColor":"#0076a9","functionColor":"#d3284b","variableColor":"#c14700","__typename":"PrismThemeSettings"},"rte":{"bgColor":"var(--lia-bs-white)","borderRadius":"var(--lia-panel-border-radius)","boxShadow":" var(--lia-panel-box-shadow)","customColor1":"#bfedd2","customColor2":"#fbeeb8","customColor3":"#f8cac6","customColor4":"#eccafa","customColor5":"#c2e0f4","customColor6":"#2dc26b","customColor7":"#f1c40f","customColor8":"#e03e2d","customColor9":"#b96ad9","customColor10":"#3598db","customColor11":"#169179","customColor12":"#e67e23","customColor13":"#ba372a","customColor14":"#843fa1","customColor15":"#236fa1","customColor16":"#ecf0f1","customColor17":"#ced4d9","customColor18":"#95a5a6","customColor19":"#7e8c8d","customColor20":"#34495e","customColor21":"#000000","customColor22":"#ffffff","defaultMessageHeaderMarginTop":"14px","defaultMessageHeaderMarginBottom":"10px","defaultMessageItemMarginTop":"0","defaultMessageItemMarginBottom":"10px","diffAddedColor":"hsla(170, 53%, 51%, 0.4)","diffChangedColor":"hsla(43, 97%, 63%, 0.4)","diffNoneColor":"hsla(0, 0%, 80%, 0.4)","diffRemovedColor":"hsla(9, 74%, 47%, 0.4)","specialMessageHeaderMarginTop":"14px","specialMessageHeaderMarginBottom":"10px","specialMessageItemMarginTop":"0","specialMessageItemMarginBottom":"10px","__typename":"RteThemeSettings"},"tags":{"bgColor":"var(--lia-bs-gray-200)","bgHoverColor":"var(--lia-bs-gray-400)","borderRadius":"var(--lia-bs-border-radius-sm)","color":"var(--lia-bs-body-color)","hoverColor":"var(--lia-bs-body-color)","fontWeight":"var(--lia-font-weight-md)","fontSize":"var(--lia-font-size-xxs)","textTransform":"UPPERCASE","letterSpacing":"0.5px","__typename":"TagsThemeSettings"},"toasts":{"borderRadius":"var(--lia-bs-border-radius)","paddingX":"12px","__typename":"ToastsThemeSettings"},"typography":{"fontFamilyBase":"Atkinson Hyperlegible","fontStyleBase":"NORMAL","fontWeightBase":"400","fontWeightLight":"300","fontWeightNormal":"400","fontWeightMd":"500","fontWeightBold":"700","letterSpacingSm":"normal","letterSpacingXs":"normal","lineHeightBase":"1.3","fontSizeBase":"15px","fontSizeXxs":"11px","fontSizeXs":"12px","fontSizeSm":"13px","fontSizeLg":"20px","fontSizeXl":"24px","smallFontSize":"14px","customFonts":[],"__typename":"TypographyThemeSettings"},"unstyledListItem":{"marginBottomSm":"5px","marginBottomMd":"10px","marginBottomLg":"15px","marginBottomXl":"20px","marginBottomXxl":"25px","__typename":"UnstyledListItemThemeSettings"},"yiq":{"light":"#ffffff","dark":"#000000","__typename":"YiqThemeSettings"},"colorLightness":{"primaryDark":0.36,"primaryLight":0.74,"primaryLighter":0.89,"primaryLightest":0.95,"infoDark":0.39,"infoLight":0.72,"infoLighter":0.85,"infoLightest":0.93,"successDark":0.24,"successLight":0.62,"successLighter":0.8,"successLightest":0.91,"warningDark":0.39,"warningLight":0.68,"warningLighter":0.84,"warningLightest":0.93,"dangerDark":0.41,"dangerLight":0.72,"dangerLighter":0.89,"dangerLightest":0.95,"__typename":"ColorLightnessThemeSettings"},"localOverride":false,"__typename":"Theme"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Loading/LoadingDot-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Loading/LoadingDot-1740415735000","value":{"title":"Loading..."},"localOverride":false},"CachedAsset:text:en_US-components/common/EmailVerification-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/common/EmailVerification-1740415735000","value":{"email.verification.title":"Email Verification Required","email.verification.message.update.email":"To participate in the community, you must first verify your email address. The verification email was sent to {email}. To change your email, visit My Settings.","email.verification.message.resend.email":"To participate in the community, you must first verify your email address. The verification email was sent to {email}. Resend email."},"localOverride":false},"CachedAsset:text:en_US-pages/tags/TagPage-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-pages/tags/TagPage-1740415735000","value":{"tagPageTitle":"Tag:\"{tagName}\" | {communityTitle}","tagPageForNodeTitle":"Tag:\"{tagName}\" in \"{title}\" | {communityTitle}","name":"Tags Page","tag":"Tag: {tagName}"},"localOverride":false},"CachedAsset:quilt:f5.prod:pages/tags/TagPage:community:zihoc95639-1742463841043":{"__typename":"CachedAsset","id":"quilt:f5.prod:pages/tags/TagPage:community:zihoc95639-1742463841043","value":{"id":"TagPage","container":{"id":"Common","headerProps":{"removeComponents":["community.widget.bannerWidget"],"__typename":"QuiltContainerSectionProps"},"items":[{"id":"tag-header-widget","layout":"ONE_COLUMN","bgColor":"var(--lia-bs-white)","showBorder":"BOTTOM","sectionEditLevel":"LOCKED","columnMap":{"main":[{"id":"tags.widget.TagsHeaderWidget","__typename":"QuiltComponent"}],"__typename":"OneSectionColumns"},"__typename":"OneColumnQuiltSection"},{"id":"messages-list-for-tag-widget","layout":"ONE_COLUMN","columnMap":{"main":[{"id":"messages.widget.messageListForNodeByRecentActivityWidget","props":{"viewVariant":{"type":"inline","props":{"useUnreadCount":true,"useViewCount":true,"useAuthorLogin":true,"clampBodyLines":3,"useAvatar":true,"useBoardIcon":false,"useKudosCount":true,"usePreviewMedia":true,"useTags":false,"useNode":true,"useNodeLink":true,"useTextBody":true,"truncateBodyLength":-1,"useBody":true,"useRepliesCount":true,"useSolvedBadge":true,"timeStampType":"conversation.lastPostingActivityTime","useMessageTimeLink":true,"clampSubjectLines":2}},"panelType":"divider","useTitle":false,"hideIfEmpty":false,"pagerVariant":{"type":"loadMore"},"style":"list","showTabs":true,"tabItemMap":{"default":{"mostRecent":true,"mostRecentUserContent":false,"newest":false},"additional":{"mostKudoed":true,"mostViewed":true,"mostReplies":false,"noReplies":false,"noSolutions":false,"solutions":false}}},"__typename":"QuiltComponent"}],"__typename":"OneSectionColumns"},"__typename":"OneColumnQuiltSection"}],"__typename":"QuiltContainer"},"__typename":"Quilt"},"localOverride":false},"CachedAsset:quiltWrapper:f5.prod:Common:1742463757226":{"__typename":"CachedAsset","id":"quiltWrapper:f5.prod:Common:1742463757226","value":{"id":"Common","header":{"backgroundImageProps":{"assetName":"header.jpg","backgroundSize":"COVER","backgroundRepeat":"NO_REPEAT","backgroundPosition":"LEFT_CENTER","lastModified":"1702932449000","__typename":"BackgroundImageProps"},"backgroundColor":"transparent","items":[{"id":"custom.widget.Beta_MetaNav","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"},{"id":"community.widget.navbarWidget","props":{"showUserName":false,"showRegisterLink":true,"style":{"boxShadow":"var(--lia-bs-box-shadow-sm)","linkFontWeight":"700","controllerHighlightColor":"hsla(30, 100%, 50%)","dropdownDividerMarginBottom":"10px","hamburgerBorderHover":"none","linkFontSize":"15px","linkBoxShadowHover":"none","backgroundOpacity":0.4,"controllerBorderRadius":"var(--lia-border-radius-50)","hamburgerBgColor":"transparent","linkTextBorderBottom":"none","hamburgerColor":"var(--lia-nav-controller-icon-color)","brandLogoHeight":"48px","linkLetterSpacing":"normal","linkBgHoverColor":"transparent","collapseMenuDividerOpacity":0.16,"paddingBottom":"10px","dropdownPaddingBottom":"15px","dropdownMenuOffset":"2px","hamburgerBgHoverColor":"transparent","borderBottom":"0","hamburgerBorder":"none","dropdownPaddingX":"10px","brandMarginRightSm":"10px","linkBoxShadow":"none","linkJustifyContent":"center","linkColor":"var(--lia-bs-primary)","collapseMenuDividerBg":"var(--lia-nav-link-color)","dropdownPaddingTop":"10px","controllerHighlightTextColor":"var(--lia-yiq-dark)","background":{"imageAssetName":"","color":"var(--lia-bs-white)","size":"COVER","repeat":"NO_REPEAT","position":"CENTER_CENTER","imageLastModified":""},"linkBorderRadius":"var(--lia-bs-border-radius-sm)","linkHoverColor":"var(--lia-bs-primary)","position":"FIXED","linkBorder":"none","linkTextBorderBottomHover":"2px solid #0C5C8D","brandMarginRight":"30px","hamburgerHoverColor":"var(--lia-nav-controller-icon-color)","linkBorderHover":"none","collapseMenuMarginLeft":"20px","linkFontStyle":"NORMAL","linkPaddingX":"10px","paddingTop":"10px","linkPaddingY":"5px","linkTextTransform":"NONE","dropdownBorderColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","controllerBgHoverColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.1)","linkDropdownPaddingX":"var(--lia-nav-link-px)","linkBgColor":"transparent","linkDropdownPaddingY":"9px","controllerIconColor":"#0C5C8D","dropdownDividerMarginTop":"10px","linkGap":"10px","controllerIconHoverColor":"#0C5C8D"},"links":{"sideLinks":[],"mainLinks":[{"children":[{"linkType":"INTERNAL","id":"migrated-link-1","params":{"boardId":"TechnicalForum","categoryId":"Forums"},"routeName":"ForumBoardPage"},{"linkType":"INTERNAL","id":"migrated-link-2","params":{"boardId":"WaterCooler","categoryId":"Forums"},"routeName":"ForumBoardPage"}],"linkType":"INTERNAL","id":"migrated-link-0","params":{"categoryId":"Forums"},"routeName":"CategoryPage"},{"children":[{"linkType":"INTERNAL","id":"migrated-link-4","params":{"boardId":"codeshare","categoryId":"CrowdSRC"},"routeName":"TkbBoardPage"},{"linkType":"INTERNAL","id":"migrated-link-5","params":{"boardId":"communityarticles","categoryId":"CrowdSRC"},"routeName":"TkbBoardPage"}],"linkType":"INTERNAL","id":"migrated-link-3","params":{"categoryId":"CrowdSRC"},"routeName":"CategoryPage"},{"children":[{"linkType":"INTERNAL","id":"migrated-link-7","params":{"boardId":"TechnicalArticles","categoryId":"Articles"},"routeName":"TkbBoardPage"},{"linkType":"INTERNAL","id":"article-series","params":{"boardId":"article-series","categoryId":"Articles"},"routeName":"TkbBoardPage"},{"linkType":"INTERNAL","id":"security-insights","params":{"boardId":"security-insights","categoryId":"Articles"},"routeName":"TkbBoardPage"},{"linkType":"INTERNAL","id":"migrated-link-8","params":{"boardId":"DevCentralNews","categoryId":"Articles"},"routeName":"TkbBoardPage"}],"linkType":"INTERNAL","id":"migrated-link-6","params":{"categoryId":"Articles"},"routeName":"CategoryPage"},{"children":[{"linkType":"INTERNAL","id":"migrated-link-10","params":{"categoryId":"CommunityGroups"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"migrated-link-11","params":{"categoryId":"F5-Groups"},"routeName":"CategoryPage"}],"linkType":"INTERNAL","id":"migrated-link-9","params":{"categoryId":"GroupsCategory"},"routeName":"CategoryPage"},{"children":[],"linkType":"INTERNAL","id":"migrated-link-12","params":{"boardId":"Events","categoryId":"top"},"routeName":"EventBoardPage"},{"children":[],"linkType":"INTERNAL","id":"migrated-link-13","params":{"boardId":"Suggestions","categoryId":"top"},"routeName":"IdeaBoardPage"},{"children":[],"linkType":"EXTERNAL","id":"Common-external-link","url":"https://community.f5.com/c/how-do-i","target":"SELF"}]},"className":"QuiltComponent_lia-component-edit-mode__lQ9Z6","showSearchIcon":false},"__typename":"QuiltComponent"},{"id":"community.widget.bannerWidget","props":{"backgroundColor":"transparent","visualEffects":{"showBottomBorder":false},"backgroundImageProps":{"backgroundSize":"COVER","backgroundPosition":"CENTER_CENTER","backgroundRepeat":"NO_REPEAT"},"fontColor":"#222222"},"__typename":"QuiltComponent"},{"id":"community.widget.breadcrumbWidget","props":{"backgroundColor":"var(--lia-bs-primary)","linkHighlightColor":"#FFFFFF","visualEffects":{"showBottomBorder":false},"backgroundOpacity":60,"linkTextColor":"#FFFFFF"},"__typename":"QuiltComponent"}],"__typename":"QuiltWrapperSection"},"footer":{"backgroundImageProps":{"assetName":null,"backgroundSize":"COVER","backgroundRepeat":"NO_REPEAT","backgroundPosition":"CENTER_CENTER","lastModified":null,"__typename":"BackgroundImageProps"},"backgroundColor":"var(--lia-bs-body-color)","items":[{"id":"custom.widget.Beta_Footer","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"},{"id":"custom.widget.Tag_Manager_Helper","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"},{"id":"custom.widget.Consent_Blackbar","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"}],"__typename":"QuiltWrapperSection"},"__typename":"QuiltWrapper","localOverride":false},"localOverride":false},"CachedAsset:text:en_US-components/common/ActionFeedback-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/common/ActionFeedback-1740415735000","value":{"joinedGroupHub.title":"Welcome","joinedGroupHub.message":"You are now a member of this group and are subscribed to updates.","groupHubInviteNotFound.title":"Invitation Not Found","groupHubInviteNotFound.message":"Sorry, we could not find your invitation to the group. The owner may have canceled the invite.","groupHubNotFound.title":"Group Not Found","groupHubNotFound.message":"The grouphub you tried to join does not exist. It may have been deleted.","existingGroupHubMember.title":"Already Joined","existingGroupHubMember.message":"You are already a member of this group.","accountLocked.title":"Account Locked","accountLocked.message":"Your account has been locked due to multiple failed attempts. Try again in {lockoutTime} minutes.","editedGroupHub.title":"Changes Saved","editedGroupHub.message":"Your group has been updated.","leftGroupHub.title":"Goodbye","leftGroupHub.message":"You are no longer a member of this group and will not receive future updates.","deletedGroupHub.title":"Deleted","deletedGroupHub.message":"The group has been deleted.","groupHubCreated.title":"Group Created","groupHubCreated.message":"{groupHubName} is ready to use","accountClosed.title":"Account Closed","accountClosed.message":"The account has been closed and you will now be redirected to the homepage","resetTokenExpired.title":"Reset Password Link has Expired","resetTokenExpired.message":"Try resetting your password again","invalidUrl.title":"Invalid URL","invalidUrl.message":"The URL you're using is not recognized. Verify your URL and try again.","accountClosedForUser.title":"Account Closed","accountClosedForUser.message":"{userName}'s account is closed","inviteTokenInvalid.title":"Invitation Invalid","inviteTokenInvalid.message":"Your invitation to the community has been canceled or expired.","inviteTokenError.title":"Invitation Verification Failed","inviteTokenError.message":"The url you are utilizing is not recognized. Verify your URL and try again","pageNotFound.title":"Access Denied","pageNotFound.message":"You do not have access to this area of the community or it doesn't exist","eventAttending.title":"Responded as Attending","eventAttending.message":"You'll be notified when there's new activity and reminded as the event approaches","eventInterested.title":"Responded as Interested","eventInterested.message":"You'll be notified when there's new activity and reminded as the event approaches","eventNotFound.title":"Event Not Found","eventNotFound.message":"The event you tried to respond to does not exist.","redirectToRelatedPage.title":"Showing Related Content","redirectToRelatedPageForBaseUsers.title":"Showing Related Content","redirectToRelatedPageForBaseUsers.message":"The content you are trying to access is archived","redirectToRelatedPage.message":"The content you are trying to access is archived","relatedUrl.archivalLink.flyoutMessage":"The content you are trying to access is archived View Archived Content"},"localOverride":false},"CachedAsset:component:custom.widget.Beta_MetaNav-en-1742463858459":{"__typename":"CachedAsset","id":"component:custom.widget.Beta_MetaNav-en-1742463858459","value":{"component":{"id":"custom.widget.Beta_MetaNav","template":{"id":"Beta_MetaNav","markupLanguage":"HANDLEBARS","style":null,"texts":null,"defaults":{"config":{"applicablePages":[],"description":"MetaNav menu at the top of every page.","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.Beta_MetaNav","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"MetaNav menu at the top of every page.","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":null,"form":null},"localOverride":false},"CachedAsset:component:custom.widget.Beta_Footer-en-1742463858459":{"__typename":"CachedAsset","id":"component:custom.widget.Beta_Footer-en-1742463858459","value":{"component":{"id":"custom.widget.Beta_Footer","template":{"id":"Beta_Footer","markupLanguage":"HANDLEBARS","style":null,"texts":null,"defaults":{"config":{"applicablePages":[],"description":"DevCentral´s custom footer.","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.Beta_Footer","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"DevCentral´s custom footer.","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":null,"form":null},"localOverride":false},"CachedAsset:component:custom.widget.Tag_Manager_Helper-en-1742463858459":{"__typename":"CachedAsset","id":"component:custom.widget.Tag_Manager_Helper-en-1742463858459","value":{"component":{"id":"custom.widget.Tag_Manager_Helper","template":{"id":"Tag_Manager_Helper","markupLanguage":"HANDLEBARS","style":null,"texts":null,"defaults":{"config":{"applicablePages":[],"description":"Helper widget to inject Tag Manager scripts into head element","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.Tag_Manager_Helper","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"Helper widget to inject Tag Manager scripts into head element","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":null,"form":null},"localOverride":false},"CachedAsset:component:custom.widget.Consent_Blackbar-en-1742463858459":{"__typename":"CachedAsset","id":"component:custom.widget.Consent_Blackbar-en-1742463858459","value":{"component":{"id":"custom.widget.Consent_Blackbar","template":{"id":"Consent_Blackbar","markupLanguage":"HTML","style":null,"texts":null,"defaults":{"config":{"applicablePages":[],"description":"","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.Consent_Blackbar","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"TEXTHTML","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":null,"form":null},"localOverride":false},"CachedAsset:text:en_US-components/community/Breadcrumb-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/community/Breadcrumb-1740415735000","value":{"navLabel":"Breadcrumbs","dropdown":"Additional parent page navigation"},"localOverride":false},"CachedAsset:text:en_US-components/tags/TagsHeaderWidget-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/tags/TagsHeaderWidget-1740415735000","value":{"tag":"{tagName}","topicsCount":"{count} {count, plural, one {Topic} other {Topics}}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageListForNodeByRecentActivityWidget-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageListForNodeByRecentActivityWidget-1740415735000","value":{"title@userScope:other":"Recent Content","title@userScope:self":"Contributions","title@board:FORUM@userScope:other":"Recent Discussions","title@board:BLOG@userScope:other":"Recent Blogs","emptyDescription":"No content to show","MessageListForNodeByRecentActivityWidgetEditor.nodeScope.label":"Scope","title@instance:1706288370055":"Content Feed","title@instance:1704319314827":"Blog Feed","title@instance:1704317906837":"Content Feed","title@instance:1702668293472":"Community Feed","title@instance:1704320290851":"My Contributions","title@instance:1703720491809":"Forum Feed","title@instance:1703028709746":"Group Content Feed","title@instance:VTsglH":"Content Feed"},"localOverride":false},"Category:category:Forums":{"__typename":"Category","id":"category:Forums","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Forum:board:TechnicalForum":{"__typename":"Forum","id":"board:TechnicalForum","forumPolicies":{"__typename":"ForumPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Forum:board:WaterCooler":{"__typename":"Forum","id":"board:WaterCooler","forumPolicies":{"__typename":"ForumPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Articles":{"__typename":"Category","id":"category:Articles","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"displayId":"Articles"},"Tkb:board:TechnicalArticles":{"__typename":"Tkb","id":"board:TechnicalArticles","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"displayId":"TechnicalArticles","nodeType":"board","conversationStyle":"TKB","title":"Technical Articles","shortTitle":"Technical Articles","parent":{"__ref":"Category:category:Articles"}},"Tkb:board:DevCentralNews":{"__typename":"Tkb","id":"board:DevCentralNews","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:GroupsCategory":{"__typename":"Category","id":"category:GroupsCategory","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:F5-Groups":{"__typename":"Category","id":"category:F5-Groups","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:CommunityGroups":{"__typename":"Category","id":"category:CommunityGroups","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Occasion:board:Events":{"__typename":"Occasion","id":"board:Events","boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"occasionPolicies":{"__typename":"OccasionPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Idea:board:Suggestions":{"__typename":"Idea","id":"board:Suggestions","boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"ideaPolicies":{"__typename":"IdeaPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:CrowdSRC":{"__typename":"Category","id":"category:CrowdSRC","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Tkb:board:codeshare":{"__typename":"Tkb","id":"board:codeshare","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Tkb:board:communityarticles":{"__typename":"Tkb","id":"board:communityarticles","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Tkb:board:security-insights":{"__typename":"Tkb","id":"board:security-insights","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Tkb:board:article-series":{"__typename":"Tkb","id":"board:article-series","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Conversation:conversation:290328":{"__typename":"Conversation","id":"conversation:290328","topic":{"__typename":"TkbTopicMessage","uid":290328},"lastPostingActivityTime":"2024-08-29T03:26:38.635-07:00","solved":false},"User:user:51154":{"__typename":"User","uid":51154,"login":"JRahm","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/images/dS01MTE1NC1uYzdSVFk?image-coordinates=0%2C0%2C1067%2C1067"},"id":"user:51154"},"TkbTopicMessage:message:290328":{"__typename":"TkbTopicMessage","subject":"Demystifying iControl REST Part 7 - Understanding Transactions","conversation":{"__ref":"Conversation:conversation:290328"},"id":"message:290328","revisionNum":2,"uid":290328,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:51154"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":3143},"postTime":"2016-08-12T14:30:00.000-07:00","lastPublishTime":"2023-06-05T22:49:39.204-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" iControl REST. It’s iControl SOAP’s baby, brother, introduced back in TMOS version 11.4 as an early access feature but released fully in version 11.5. Several articles on basic usage have been written about the rest interface so the intent here isn’t basic use, but rather to demystify some of the finer details of using the API. \n\n A few months ago, a question in Q&A from community member spirrello asking how to update a tcp profile on a virtual. He was using bigsuds, the python wrapper for the soap interface. For the rest interface on this particular object, this is easy; just use the put method and supply the payload mapping the updated profile. But for soap, this requires a transaction. There are some changes to BIG-IP via the rest interface, however, like updating an ssl cert or key, that likewise will require a transaction to accomplish. In this article, I’ll show you how to use transactions with the rest interface. \n\n The Fine Print \n\n From the iControl REST user guide, the life cycle of a transaction progresses through three phases: \n\n Creation - This phase occurs when the transaction is created using a POST command. Modification - This phase occurs when commands are added to the transaction, or changes are made to the sequence of commands in the transaction. Commit - This phase occurs when iControl REST runs the transaction. \n\n To create a transaction, post to /tm/transaction \n\n \n POST https://192.168.25.42/mgmt/tm/transaction\n\n {}\n\n Response:\n\n {\n \"transId\":1389812351,\n \"state\":\"STARTED\",\n \"timeoutSeconds\":30,\n \"kind\":\"tm:transactionstate\",\n \"selfLink\":\"https://localhost/mgmt/tm/transaction/1389812351?ver=11.5.0\"\n } \n\n Note the transId, the state, and the timeoutSeconds. You'll need the transId to add or re-sequence commands within the transaction, and the transaction will expire after 30 seconds if no commands are added. You can list all transactions, or the details of a specific transaction with a get request. \n\n \n GET https://192.168.25.42/mgmt/tm/transaction\n GET https://192.168.25.42/mgmt/tm/transaction/transId \n\n To add a command to the transaction, you use the normal method uris, but include the X-F5-REST-Coordination-Id header. This example creates a pool with a single member. \n\n \n POST https://192.168.25.42/mgmt/tm/ltm/pool\n X-F5-REST-Coordination-Id:1389812351\n {\n \"name\":\"tcb-xact-pool\",\n \"members\": [ {\"name\":\"192.168.25.32:80\",\"description\":\"First pool for transactions\"} ]\n } \n\n Not a great example because there is no need for a transaction here, but we'll roll with it! There are several other option methods for interrogating the transaction itself, see the user guide for details. Now we can commit the transaction. To do that, you reference the transaction id in the URI, remove the X-F5-REST-Coordination-Id header and use the patch method with payload key/value state: VALIDATING . \n\n \n PATCH https://localhost/mgmt/tm/transaction/1389812351\n { \"state\":\"VALIDATING\" } \n\n That's all there is to it! Now that you've seen the nitty gritty details, let's take a look at some code samples. \n\n Roll Your Own \n\n In this example, I am needing to update and ssl key and certificate. If you try to update the cert or the key, it will complain that they do not match, so you need to update both at the same time. Assuming you are writing all your code from scratch, this is all it takes in python. Note on line 21 I post with an empty payload, and then on line 23, I add the header with the transaction id. I make my modifications and then in line 31, I remove the header, and finally on line 32, I patch to the transaction id with the appropriate payload. \n\n \n import json\n import requests\n\n btx = requests.session()\n btx.auth = (f5_user, f5_password)\n btx.verify = False\n btx.headers.update({'Content-Type':'application/json'})\n urlb = 'https://{0}/mgmt/tm'.format(f5_host)\n\n domain = 'mydomain.local_sslobj'\n chain = 'mychain_sslobj\n\n try:\n key = btx.get('{0}/sys/file/ssl-key/~Common~{1}'.format(urlb, domain))\n cert = btx.get('{0}/sys/file/ssl-cert/~Common~{1}'.format(urlb, domain))\n chain = btx.get('{0}/sys/file/ssl-cert/~Common~{1}'.format(urlb, 'chain'))\n\n if (key.status_code == 200) and (cert.status_code == 200) and (chain.status_code == 200):\n\n # use a transaction\n txid = btx.post('{0}/transaction'.format(urlb), json.dumps({})).json()['transId']\n # set the X-F5-REST-Coordination-Id header with the transaction id\n btx.headers.update({'X-F5-REST-Coordination-Id': txid})\n\n # make modifications\n modkey = btx.put('{0}/sys/file/ssl-key/~Common~{1}'.format(urlb, domain), json.dumps(keyparams))\n modcert = btx.put('{0}/sys/file/ssl-cert/~Common~{1}'.format(urlb, domain), json.dumps(certparams))\n modchain = btx.put('{0}/sys/file/ssl-cert/~Common~{1}'.format(urlb, 'le-chain'), json.dumps(chainparams))\n\n # remove header and patch to commit the transaction\n del btx.headers['X-F5-REST-Coordination-Id']\n cresult = btx.patch('{0}/transaction/{1}'.format(urlb, txid), json.dumps({'state':'VALIDATING'})).json() \n\n A Little Help from a Friend \n\n The f5-common-python library was released a few months ago to relieve you of a lot of the busy work with building requests. This is great, especially for transactions. To simplify the above code just to the transaction steps, consider: \n\n \n # use a transaction\n txid = btx.post('{0}/transaction'.format(urlb), json.dumps({})).json()['transId']\n # set the X-F5-REST-Coordination-Id header with the transaction id\n btx.headers.update({'X-F5-REST-Coordination-Id': txid})\n\n# do stuff here\n\n # remove header and patch to commit the transaction\n del btx.headers['X-F5-REST-Coordination-Id']\n cresult = btx.patch('{0}/transaction/{1}'.format(urlb, txid), json.dumps({'state':'VALIDATING'})).json() \n\n With the library, it's simplified to: \n\n \n tx = b.tm.transactions.transaction\n with TransactionContextManager(tx) as api:\n # do stuff here\n api.do_stuff \n\n Yep, it's that simple. So if you haven't checked out the f5-common-python library, I highly suggest you do! I'll be writing about how to get started using it next week, and perhaps a follow up on how to contribute to it as well, so stay tuned! ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"6407","kudosSumWeight":2,"repliesCount":9,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:286793":{"__typename":"Conversation","id":"conversation:286793","topic":{"__typename":"TkbTopicMessage","uid":286793},"lastPostingActivityTime":"2024-01-05T16:01:57.515-08:00","solved":false},"TkbTopicMessage:message:286793":{"__typename":"TkbTopicMessage","subject":"Demystifying iControl REST Part 6: Token-Based Authentication","conversation":{"__ref":"Conversation:conversation:286793"},"id":"message:286793","revisionNum":2,"uid":286793,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:51154"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":19311},"postTime":"2015-11-18T03:00:00.000-08:00","lastPublishTime":"2024-01-05T16:01:57.515-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" iControl REST. It’s iControl SOAP’s baby, brother, introduced back in TMOS version 11.4 as an early access feature but released fully in version 11.5. \n Several articles on basic usage have been written on iControl REST so the intent here isn’t basic use, but rather to demystify some of the finer details of using the API. This article will cover the details on how to retrieve and use an authentication token from the BIG-IP using iControl REST and the python programming language. This token is used in place of basic authentication on API calls, which is a requirement for external authentication. Note that for configuration changes, version 12.0 or higher is required as earlier versions will trigger an un-authorized error. \n \n The tacacs config in this article is dependent on a version that I am no longer able to get installed on a modern linux flavor. Instead, try this Dockerized tacacs+ server for your testing. \n \n The Fine Print \n The details of the token provider are here in the wiki. We’ll focus on a provider not listed there: tmos. This provider instructs the API interface to use the provider that is configured in tmos. For this article, I’ve configured a tacacs server and the BIG-IP with custom remote roles as shown below to show BIG-IP version 12’s iControl REST support for remote authentication and authorization. Details for how this configuration works can be found in the tacacs+ article I wrote a while back. \n BIG-IP tacacs+ configuration \n auth remote-role {\n role-info {\n adm {\n attribute F5-LTM-User-Info-1=adm\n console %F5-LTM-User-Console\n line-order 1\n role %F5-LTM-User-Role\n user-partition %F5-LTM-User-Partition\n }\n mgr {\n attribute F5-LTM-User-Info-1=mgr\n console %F5-LTM-User-Console\n line-order 2\n role %F5-LTM-User-Role\n user-partition %F5-LTM-User-Partition\n }\n }\n}\nauth remote-user { }\nauth source {\n type tacacs\n}\nauth tacacs system-auth {\n debug enabled\n protocol ip\n secret $M$Zq$T2SNeIqxi29CAfShLLqw8Q==\n servers { 172.16.44.20 }\n service ppp\n} \n Tacacs+ Server configuration \n id = tac_plus {\ndebug = PACKET AUTHEN AUTHOR\n\naccess log = /var/log/access.log\naccounting log = /var/log/acct.log\n\nhost = world {\naddress = ::/0\nprompt = \"\\nAuthorized Access Only!\\nTACACS+ Login\\n\"\nkey = devcentral\n}\n\ngroup = adm {\nservice = ppp {\nprotocol = ip {\nset F5-LTM-User-Info-1 = adm\nset F5-LTM-User-Console = 1\nset F5-LTM-User-Role = 0\nset F5-LTM-User-Partition = all\n}\n}\n}\n\n group = mgr {\n service = ppp {\n protocol = ip {\n set F5-LTM-User-Info-1 = mgr\n set F5-LTM-User-Console = 1\n set F5-LTM-User-Role = 100\n set F5-LTM-User-Partition = all\n }\n }\n }\n\nuser = user_admin {\npassword = clear letmein00\nmember = adm\n}\nuser = user_mgr {\npassword = clear letmein00\nmember = mgr\n}\n} \n  Basic Requirements \n Before we look at code, however, let’s take a look at the json payload requirements, followed by response data from a query using Chrome’s Advanced REST Client plugin. First, since we are sending json payload, we need to add the Content-Type: application/json header to the query. The payload we are sending with the post looks like this: \n {\n\"username\": \"remote_auth_user\",\n\"password\": \"remote_auth_password\",\n\"loginProviderName\": \"tmos\"\n} \n You submit the same remote authentication credentials in the initial basic authentication as well, no need to have access to the default admin account credentials. A successful query for a token returns data like this: \n {\nusername: \"user_admin\"\nloginReference: {\nlink: \"https://localhost/mgmt/cm/system/authn/providers/tmos/1f44a60e-11a7-3c51-a49f-82983026b41b/login\"\n}-\ntoken: {\nuuid: \"4d1bd79f-dca7-406b-8627-3ad262628f31\"\nname: \"5C0F982A0BF37CBE5DE2CB8313102A494A4759E5704371B77D7E35ADBE4AAC33184EB3C5117D94FAFA054B7DB7F02539F6550F8D4FA25C4BFF1145287E93F70D\"\ntoken: \"5C0F982A0BF37CBE5DE2CB8313102A494A4759E5704371B77D7E35ADBE4AAC33184EB3C5117D94FAFA054B7DB7F02539F6550F8D4FA25C4BFF1145287E93F70D\"\nuserName: \"user_admin\"\nuser: {\nlink: \"https://localhost/mgmt/cm/system/authn/providers/tmos/1f44a60e-11a7-3c51-a49f-82983026b41b/users/34ba3932-bfa3-4738-9d55-c81a1c783619\"\n}-\ngroupReferences: [1]\n0: {\nlink: \"https://localhost/mgmt/cm/system/authn/providers/tmos/1f44a60e-11a7-3c51-a49f-82983026b41b/user-groups/21232f29-7a57-35a7-8389-4a0e4a801fc3\"\n}-\n-\ntimeout: 1200\nstartTime: \"2015-11-17T19:38:50.415-0800\"\naddress: \"172.16.44.1\"\npartition: \"[All]\"\ngeneration: 1\nlastUpdateMicros: 1447817930414518\nexpirationMicros: 1447819130415000\nkind: \"shared:authz:tokens:authtokenitemstate\"\nselfLink: \"https://localhost/mgmt/shared/authz/tokens/4d1bd79f-dca7-406b-8627-3ad262628f31\"\n}-\ngeneration: 0\nlastUpdateMicros: 0\n} \n Among many other fields, you can see the token field with a very long hexadecimal token. That’s what we need to authenticate future API calls. \n Requesting the token programmatically \n In order to request the token, you first have to supply basic auth credentials like normal. This is currently required to access the /mgmt/shared/authn/login API location. The basic workflow is as follows (with line numbers from the code below in parentheses): \n \n Make a POST request to BIG-IP with basic authentication header and json payload with username, password, and the login provider (9-16, 41-47) \n Remove the basic authentication (49) \n Add the token from the post response to the X-F5-Auth-Token header (50) \n Continue further requests like normal. In this example, we’ll create a pool to verify read/write privileges. (1-6, 52-53) \n \n And here’s the code (in python) to make that happen: \n def create_pool(bigip, url, pool):\n payload = {}\n payload['name'] = pool\n\n pool_config = bigip.post(url, json.dumps(payload)).json()\n return pool_config\n\n\ndef get_token(bigip, url, creds):\n payload = {}\n payload['username'] = creds[0]\n payload['password'] = creds[1]\n payload['loginProviderName'] = 'tmos'\n\n token = bigip.post(url, json.dumps(payload)).json()['token']['token']\n return token\n\n\nif __name__ == \"__main__\":\n import os, requests, json, argparse, getpass\n requests.packages.urllib3.disable_warnings()\n\n parser = argparse.ArgumentParser(description='Remote Authentication Test - Create Pool')\n\n parser.add_argument(\"host\", help='BIG-IP IP or Hostname', )\n parser.add_argument(\"username\", help='BIG-IP Username')\n parser.add_argument(\"poolname\", help='Key/Cert file names (include the path.)')\n args = vars(parser.parse_args())\n\n hostname = args['host']\n username = args['username']\n poolname = args['poolname']\n\n print \"%s, enter your password: \" % args['username'],\n password = getpass.getpass()\n\n url_base = 'https://%s/mgmt' % hostname\n url_auth = '%s/shared/authn/login' % url_base\n url_pool = '%s/tm/ltm/pool' % url_base\n\n b = requests.session()\n b.headers.update({'Content-Type':'application/json'})\n b.auth = (username, password)\n b.verify = False\n\n token = get_token(b, url_auth, (username, password))\n print '\\nToken: %s\\n' % token\n\n b.auth = None\n b.headers.update({'X-F5-Auth-Token': token})\n\n response = create_pool(b, url_pool, poolname)\n print '\\nNew Pool: %s\\n' % response \n Running this script from the command line, we get the following response: \n FLD-ML-RAHM:scripts rahm$ python remoteauth.py 172.16.44.15 user_admin myNewestPool1\nPassword: user_admin, enter your password:\n \nToken: 2C61FE257C7A8B6E49C74864240E8C3D3592FDE9DA3007618CE11915F1183BF9FBAF00D09F61DE15FCE9CAB2DC2ACC165CBA3721362014807A9BF4DEA90BB09F\n\n\nNew Pool: {u'generation': 453, u'minActiveMembers': 0, u'ipTosToServer': u'pass-through', u'loadBalancingMode': u'round-robin', u'allowNat': u'yes', u'queueDepthLimit': 0, u'membersReference': {u'isSubcollection': True, u'link': u'https://localhost/mgmt/tm/ltm/pool/~Common~myNewestPool1/members?ver=12.0.0'}, u'minUpMembers': 0, u'slowRampTime': 10, u'minUpMembersAction': u'failover', u'minUpMembersChecking': u'disabled', u'queueTimeLimit': 0, u'linkQosToServer': u'pass-through', u'queueOnConnectionLimit': u'disabled', u'fullPath': u'myNewestPool1', u'kind': u'tm:ltm:pool:poolstate', u'name': u'myNewestPool1', u'allowSnat': u'yes', u'ipTosToClient': u'pass-through', u'reselectTries': 0, u'selfLink': u'https://localhost/mgmt/tm/ltm/pool/myNewestPool1?ver=12.0.0', u'serviceDownAction': u'none', u'ignorePersistedWeight': u'disabled', u'linkQosToClient': u'pass-through'}\n \n You can test this out in the Chrome Advanced Rest Client plugin, or from the command line with curl or any other language supporting REST clients as well, I just use python for the examples well, because I like it. I hope you all are digging into iControl REST! What questions do you have? What else would you like clarity on? Drop a comment below. ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"8919","kudosSumWeight":0,"repliesCount":42,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:286518":{"__typename":"Conversation","id":"conversation:286518","topic":{"__typename":"TkbTopicMessage","uid":286518},"lastPostingActivityTime":"2023-11-28T16:39:49.516-08:00","solved":false},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODY1MTgtMTE1MTJpMjkwOTkyOTM4MzQ4REM1MA?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODY1MTgtMTE1MTJpMjkwOTkyOTM4MzQ4REM1MA?revision=1","title":"0151T000003d6Y3QAI.png","associationType":"BODY","width":300,"height":104,"altText":null},"TkbTopicMessage:message:286518":{"__typename":"TkbTopicMessage","subject":"Demystifying iControl REST Part 1 - Understanding the request URI","conversation":{"__ref":"Conversation:conversation:286518"},"id":"message:286518","revisionNum":1,"uid":286518,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:51154"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":5828},"postTime":"2015-06-17T08:00:00.000-07:00","lastPublishTime":"2015-06-17T08:00:00.000-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" iControl REST. It’s iControl SOAP’s baby brother, introduced back in TMOS version 11.4 as an early access feature but was released fully in version 11.5. \n\n \n\n  Several articles on basic usage have been written on iControl REST (see the resources at the bottom of this article) so the intent here isn’t basic use, but rather to demystify some of the finer details of using the API. This article is the first of a four part series and will cover how the URI path plays a role in how the API functions. \n\n Examining the REST interface URI \n\n With iControl SOAP, all the interfaces and methods are defined in the WSDLs. With REST, the bulk of the interface and method is part of the URI. Take for example a request to get the list of iRules on a BIG-IP. \n\n https://x.x.x.x/mgmt/tm/ltm/rule \n\n With a simple get request with the appropriate headers and credentials (see below for curl and python examples,) this breaks down to the Base URI, the Module URI, and the Sub-Module URI. \n\n \n#python example\n>>> import requests\n>>> import json\n>>> b = requests.session()\n>>> b.auth = ('admin', 'admin')\n>>> b.verify = False\n>>> b.headers.update({'Content-Type':'application/json'})\n>>> b.get('https://172.16.44.128/mgmt/tm/ltm/rule')\n\n\n#curl example\ncurl -k -u admin:admin -H “Content-Type: application/json” -X GET https://172.16.44.128/mgmt/tm/ltm/rule\n \n\n Beyond the Sub-Module URI is the component URI. \n\n https://x.x.x.x/mgmt/tm/ltm/rule/testlog \n\n The component URI is the spot that snags most beginners. When creating a new configuration object on an F5, it is fairly obvious which URI to use for the REST call. If you were creating a new virtual server, it would be /mgmt/tm/ltm/virtual, while a new pool would be /mgmt/tm/ltm/pool. Thus a REST call to create a new pool on an LTM with the IP address 172.16.44.128 would look like the following: \n\n \n#python example\n>>> import requests\n>>> import json\n>>> b = requests.session()\n>>> b.auth = ('admin', 'admin')\n>>> b.verify = False\n>>> b.headers.update({'Content-Type':'application/json'})\n\n>>> pm = ['192.168.25.32:80', '192.168.25.33:80']\n>>> payload = { }\n>>> payload['kind'] = 'tm:ltm:pool:poolstate'\n>>> payload['name'] = 'tcb-pool'\n>>> payload['members'] = [ {'kind': 'ltm:pool:members', 'name': member } for member in pm]\n>>> b.post('https://172.16.44.128/mgmt/tm/ltm/pool', data=json.dumps(payload))\n\n\n#curl example\ncurl -k -u admin:admin -H \"Content-Type: \\\napplication/json\" -X POST -d \\\n'{\"name\":\"tcb-pool\",\"members\":[ \\\n{\"name\":\"192.168.25.32:80\",\"description\":\"first member”}, \\\n{\"name\":\"192.168.25.33:80\",\"description\":\"second member”} ] }' \\\nhttps://172.16.44.128/mgmt/tm/ltm/pool \n\n The call would create the pool “tcb-pool” with members at 192.168.25.32:80 and 192.168.25.33:80.  All other aspects of the pool would be the defaults.  Thus this pool would be created in the Common partition, have the Round Robin load balancing method, and no monitor. At first glance, some programmers would then modify the pool “tcb-pool” with a command like the following (same payload in python, added the .text attribute to see the error response on the requests object): \n\n \n#python example\n>>> b.put('https://172.16.44.128/mgmt/tm/ltm/pool', data=json.dumps(payload)).text\n#return data\nu'{\"code\":403,\"message\":\"Operation is not supported on component /ltm/pool.\",\"errorStack\":[]}'\n\n#curl example\ncurl -k -u admin:admin -H \"Content-Type: \\\napplication/json\" -X PUT -d \\\n'{\"name\":\"tcb-pool\",\"members\":[ \\\n{\"name\":\"192.168.25.32:80\",\"description\":\"first member\"}\n{\"name\":\"192.168.25.33:80\",\"description\":\"second member\"} ] }' \\\nhttps://172.16.44.128/mgmt/tm/ltm/pool\n#return data\n{\"code\":403,\"message\":\"Operation is not supported on component /ltm/pool.\",\"errorStack\":[]}\n \n\n You can see because they use the sub module URI used to create the pool this returns a 403 error. The command fails because one is trying to modify a specific pool at the generic pool level. Now that the pool exists, one must use the URI that specifies the pool. Thus, the correct command would be: \n\n \n#python example\n>>> b.put('https://172.16.44.128/mgmt/tm/ltm/pool/~Common~tcb-pool', data=json.dumps(payload))\n\n#curl example\ncurl -k -u admin:admin -H \"Content-Type: \\\napplication/json\" -X PUT -d \\\n'{\"members\":[ \\\n{\"name\":\"192.168.25.32:80\",\"description\":\"first member\"}\n{\"name\":\"192.168.25.33:80\",\"description\":\"second member\"} ] }' \\\nhttps://172.16.44.128/mgmt/tm/ltm/pool/~Common~tcb-pool\n \n\n We add the ~Common~ in front of the pool name because it is in the Common partition. However, this would also work with https://172.16.44.128/mgmt/tm/ltm/pool/tcb-pool. It is just good practice to explicitly insert the partition name since not all configuration objects will be in the default Common partition. Because we specify the pool in the URI, it is no longer necessary to have the “name” key value pair. \n\n In practice, programmers usually correctly modify items such as virtual servers and pools. However, we encounter this confusion much more often in configuration items that are ifiles. This may be because the creation of configuration items that are ifiles is a 3-step process. For instance, in order to create an external data group, one would first scp the file to 172.16.44.128/config/filestore/data_mda_1, then issue 2 Rest commands: \n\n \ncurl -sk -u admin:admin -H \"Content-Type: application/json\" -X POST -d '{\"name\":\"data_mda_1\",\"type\":\"string\",\"source-path\":\"file:///config/filestore/data_mda_1\"}' https://172.16.44.128/mgmt/tm/sys/file/data-group\ncurl -sk -u admin:admin -H \"Content-Type: application/json\" -X POST -d '{\"name\":\"dg_mda\",\"external-file-name\":\"/Common/data_mda_1\"}' https://172.16.44.128/mgmt/tm/ltm/data-group/external/ \n\n To update the external data group, many programmers first try something like the following: \n\n \ncurl -sk -u admin:admin -H \"Content-Type: application/json\" -X POST -d '{\"name\":\"data_mda_2\",\"type\":\"string\",\"source-path\":\"file:///config/filestore/data_mda_2”}’ https://172.16.44.128/mgmt/tm/sys/file/data-group\ncurl -sk -u admin:admin -H \"Content-Type: application/json\" -X PUT -d '{\"name\":\"dg_mda\",\"external-file-name\":\"/Common/data_mda_2\"}' https://172.16.44.128/mgmt/tm/ltm/data-group/external/ \n\n The first command works because we are creating a new ifile object. However, the second command fails because we are trying to modify a specific external data group at the generic external data group level. The proper command is: \n\n \ncurl -sk -u admin:admin -H \"Content-Type: application/json\" -X PUT -d '{\"external-file-name\":\"/Common/data_mda_2\"}' https://172.16.44.128/mgmt/tm/ltm/data-group/external/dg_mda \n\n The python code gets a little more complex with the data-group examples, so I've uploaded it to the codeshare here. Much thanks to Pat Chang for the bulk of the content in this article. Stay tuned for part 2, where we'll cover sub collections and how to use them. ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"7079","kudosSumWeight":1,"repliesCount":8,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODY1MTgtMTE1MTJpMjkwOTkyOTM4MzQ4REM1MA?revision=1\"}"}}],"totalCount":1,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:286689":{"__typename":"Conversation","id":"conversation:286689","topic":{"__typename":"TkbTopicMessage","uid":286689},"lastPostingActivityTime":"2023-08-04T09:24:35.305-07:00","solved":false},"TkbTopicMessage:message:286689":{"__typename":"TkbTopicMessage","subject":"Demystifying iControl REST Part 5: Transferring Files","conversation":{"__ref":"Conversation:conversation:286689"},"id":"message:286689","revisionNum":5,"uid":286689,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:51154"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":9144},"postTime":"2015-11-17T03:00:00.000-08:00","lastPublishTime":"2023-08-04T09:24:35.305-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":"  iControl REST. It’s iControl SOAP’s baby, brother, introduced back in TMOS version 11.4 as an early access feature but released fully in version 11.5. \n Several articles on basic usage have been written on iControl REST so the intent here isn’t basic use, but rather to demystify some of the finer details of using the API. This article will cover the details on how to transfer files to/from the BIG-IP using iControl REST and the python programming language. (Note: this functionality requires 12.0+.) \n The REST File Transfer Worker \n The file transfer worker allows a client to transfer files through a series of GET operations for downloads and POST operations for uploads. The Content-Range header is used for both as a means to chunk the content. For downloads, the worker listens on the following interfaces. \n \n \n \n Description \n Method \n URI \n File Location \n \n \n Download a File \n GET \n /mgmt/cm/autodeploy/software-image-downloads/ \n /shared/images/ \n \n \n Upload an Image File \n POST \n /mgmt/cm/autodeploy/software-image-uploads/ \n /shared/images/ \n \n \n Upload a File \n POST \n /mgmt/shared/file-transfer/uploads/ \n /var/config/rest/downloads/ \n \n \n Download a QKView \n GET \n /mgmt/shared/file-transfer/qkview-downloads/ \n /var/tmp/ \n \n \n Download a UCS \n GET \n /mgmt/shared/file-transfer/ucs-downloads/ \n /var/local/ucs/ \n \n \n Upload ASM Policy \n POST \n /mgmt/tm/asm/file-transfer/uploads/ \n /var/ts/var/rest/ \n \n \n Download ASM Policy \n GET \n /mgmt/tm/asm/file-transfer/downloads/ \n /var/ts/var/rest/ \n \n \n \n Binary and text files are supported. The magic in the transfer is the Content-Range header, which has the following format: \n Content-Range: start-end/filesize \n Where start/end are the chunk's delimiters in the file and filesize is well, the file size. Any file larger than 1M needs to be chunked with this header as that limit is enforced by the worker. This is done to avoid potential denial of service attacks and out of memory errors. There are benefits of chunking as well:  \n \n Accurate progress bars \n Resuming interrupted downloads \n Random access to file content possible  \n \n Uploading a File \n The function is shown below. Note that whereas normally with the REST API the Content-Type is application/json, with file transfers that changes to application/octet-stream. The workflow for the function works like this (line number in parentheses) : \n \n Set the Chunk Size (3) \n Set the Content-Type header (4-6) \n Open the file (7) \n Get the filename (apart from the path) from the absolute path (8) \n If the extension is an .iso file (image) put it in /shared/images, otherwise it’ll go in /var/config/rest/downloads (9-12) \n Disable ssl warnings requests (required with my version: 2.8.1. YMMV) (14) \n Set the total file size for use with the Content-Range header (15) \n Set the start variable to 0 (17) \n Begin loop to iterate through the file and upload in chunks (19) \n Read data from the file and if there is no more data, break the loop (20-22) \n set the current bytes read, if less than the chunk size, then this is the last chunk, so set the end to the size from step 7. Otherwise, add current bytes length to the start value and set that as the end. (24-28) \n Set the Content-Range header value and then add that to the header (30-31) \n Make the POST request, uploading the content chunk (32-36) \n Increment the start value by the current bytes content length (38) \n \n def _upload(host, creds, fp):\n\n chunk_size = 512 * 1024\n headers = {\n 'Content-Type': 'application/octet-stream'\n }\n fileobj = open(fp, 'rb')\n filename = os.path.basename(fp)\n if os.path.splitext(filename)[-1] == '.iso':\n uri = 'https://%s/mgmt/cm/autodeploy/software-image-uploads/%s' % (host, filename)\n else:\n uri = 'https://%s/mgmt/shared/file-transfer/uploads/%s' % (host, filename)\n\n requests.packages.urllib3.disable_warnings()\n size = os.path.getsize(fp)\n\n start = 0\n\n while True:\n file_slice = fileobj.read(chunk_size)\n if not file_slice:\n break\n\n current_bytes = len(file_slice)\n if current_bytes < chunk_size:\n end = size\n else:\n end = start + current_bytes\n\n content_range = \"%s-%s/%s\" % (start, end - 1, size)\n headers['Content-Range'] = content_range\n requests.post(uri,\n auth=creds,\n data=file_slice,\n headers=headers,\n verify=False)\n\n start += current_bytes \n Downloading a File \n Downloading is very similar but there are some differences. Here is the workflow that is different, followed by the code. Note that the local path where the file will be downloaded to is given as part of the filename. \n \n URI is set to downloads worker. The only supported download directory at this time is /shared/images. (8) \n Open the local file so received data can be written to it (11) \n Make the request (22-26) \n If response code is 200 and if size is greater than 0, increment the current bytes and write the data to file, otherwise exit the loop (28-40) \n Set the value of the returned Content-Range header to crange and if initial size (0), set the file size to the size variable (42-46) \n If the file is smaller than the chunk size, adjust the chunk size down to the total file size and continue (51-55) \n Do the math to get ready to download the next chunk (57-62) \n \n def _download(host, creds, fp):\n chunk_size = 512 * 1024\n\n headers = {\n 'Content-Type': 'application/octet-stream'\n }\n filename = os.path.basename(fp)\n uri = 'https://%s/mgmt/cm/autodeploy/software-image-downloads/%s' % (host, filename)\n requests.packages.urllib3.disable_warnings()\n\n with open(fp, 'wb') as f:\n start = 0\n end = chunk_size - 1\n size = 0\n current_bytes = 0\n\n while True:\n content_range = \"%s-%s/%s\" % (start, end, size)\n headers['Content-Range'] = content_range\n\n #print headers\n resp = requests.get(uri,\n auth=creds,\n headers=headers,\n verify=False,\n stream=True)\n\n if resp.status_code == 200:\n # If the size is zero, then this is the first time through the\n # loop and we don't want to write data because we haven't yet\n # figured out the total size of the file.\n if size > 0:\n current_bytes += chunk_size\n for chunk in resp.iter_content(chunk_size):\n f.write(chunk)\n\n # Once we've downloaded the entire file, we can break out of\n # the loop\n if end == size:\n break\n\n crange = resp.headers['Content-Range']\n\n # Determine the total number of bytes to read\n if size == 0:\n size = int(crange.split('/')[-1]) - 1\n\n # If the file is smaller than the chunk size, BIG-IP will\n # return an HTTP 400. So adjust the chunk_size down to the\n # total file size...\n if chunk_size > size:\n end = size\n\n # ...and pass on the rest of the code\n continue\n\n start += chunk_size\n\n if (current_bytes + chunk_size) > size:\n end = size\n else:\n end = start + chunk_size - 1 \n Now you know how to upload and download files. Let’s do something with it! \n A Use Case - Upload Cert & Key to BIG-IP and Create a Clientssl Profile! \n This whole effort was sparked by a use case in Q&A, so I had to deliver the goods with more than just moving files around. The complete script is linked at the bottom, but there are a few steps required to get to a clientssl certificate: \n \n Upload the key & certificate \n Create the file object for key/cert \n Create the clientssl profile \n \n You know how to do step 1 now. Step 2 is to create the file object for the key and certificate. After a quick test to see which file is the certificate, you set both files, build the payload, then make the POST requests to bind the uploaded files to the file object. \n def create_cert_obj(bigip, b_url, files):\n\n f1 = os.path.basename(files[0])\n f2 = os.path.basename(files[1])\n if f1.endswith('.crt'):\n certfilename = f1\n keyfilename = f2\n else:\n keyfilename = f1\n certfilename = f2\n\n certname = f1.split('.')[0]\n\n payload = {}\n payload['command'] = 'install'\n payload['name'] = certname\n\n # Map Cert to File Object\n payload['from-local-file'] = '/var/config/rest/downloads/%s' % certfilename\n bigip.post('%s/sys/crypto/cert' % b_url, json.dumps(payload))\n\n # Map Key to File Object\n payload['from-local-file'] = '/var/config/rest/downloads/%s' % keyfilename\n bigip.post('%s/sys/crypto/key' % b_url, json.dumps(payload))\n\n return certfilename, keyfilename \n Notice we return the key/cert filenames so they can be used for step 3 to establish the clientssl profile. In this example, I name the file object and the clientssl profile to the name of the certfilename (minus the extension) but you can alter this to allow the objects names to be provided. To build the profile, just create the payload with the custom key/cert and make the POST request and you are done! \n def create_ssl_profile(bigip, b_url, certname, keyname):\n payload = {}\n payload['name'] = certname.split('.')[0]\n payload['cert'] = certname\n payload['key'] = keyname\n bigip.post('%s/ltm/profile/client-ssl' % b_url, json.dumps(payload)) \n Much thanks to Tim Rupp who helped me get across the finish line with some counting and rest worker errors we were troubleshooting on the download function. \n Get the Code \n \n Upload a File \n Download a File \n Upload Cert/Key & Build a Clientssl Profile \n \n   ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"10046","kudosSumWeight":4,"repliesCount":45,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:289135":{"__typename":"Conversation","id":"conversation:289135","topic":{"__typename":"TkbTopicMessage","uid":289135},"lastPostingActivityTime":"2023-06-05T22:55:30.807-07:00","solved":false},"TkbTopicMessage:message:289135":{"__typename":"TkbTopicMessage","subject":"Demystifying iControl REST: Merging BIG-IP Config Files","conversation":{"__ref":"Conversation:conversation:289135"},"id":"message:289135","revisionNum":2,"uid":289135,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:51154"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":1032},"postTime":"2016-04-21T08:30:00.000-07:00","lastPublishTime":"2023-06-05T22:55:30.807-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" A coworker/friend of mine here at F5 was working last week on some super secret project I hope I’ll get to see soon and reached out on the best approach for merging config files via iControl REST. The command in tmsh tmsh load sys config merge file “file” is simple enough, but there are a few things we need to solve for this to work remotely. First, we need to get the file to the BIG-IP. Second, we need to run the merge command. Finally, we need to clean up that file so we don’t leave unnecessary remnants. So let’s address these one by one. \n\n Uploading the File \n\n This is the easy part! I’ve already written stolen this code from another coworker and shared that with the community in part 5 of this Demystifying iControl REST series. Bottom line, there is a file worker that you can use to upload files. That’s the good news. The bad news is that you cannot direct that file to a destination of your choosing, it’ll go to /var/config/rest/downloads or /shared/images, depending on the URL you specify in your transfer. More on that when we address the third problem below. \n\n Merging the File \n\n As shown in the introduction, the tmsh command is simple. But what does that look like in the REST call? Here’s the breakdown: \n\n URL: https://bigiphostname/mgmt/tm/sys/config Method: POST Payload: {“command”:”load”, “options”:[{“file”: “/var/config/rest/downloads/uploaded_file_name”, “merge”:true}]} \n\n The URL sets the tmsh path (tmsh sys config,) and the tmsh command is established in the payload, with those command line options following. In python, that makes for a simple function. \n\n \ndef _merge_config(host, creds, file):\n requests.packages.urllib3.disable_warnings()\n \n b_url = 'https://%s/mgmt/tm/sys/config' % host\n b = requests.session()\n b.auth = creds\n b.verify = False\n b.headers.update({'Content-Type': 'application/json'})\n \n \n options = {}\n options['file'] = '/var/config/rest/downloads/%s' % file\n options['merge'] = True\n \n payload = {}\n payload['command'] = 'load'\n payload['options'] = [options]\n \n try:\n merge = b.post(b_url, json.dumps(payload))\n if merge.status_code is not 200:\n print \"Merge failed, check rest log file\"\n exit()\n except Exception, e:\n print e \n\n Cleaning up the File \n\n Now that the merge has occurred, we no longer need the file taking up space on the filesystem. Because the upload directory is /var/config/rest/downloads, the space on the /var partition is not nearly as large (a tenth on my VE image) as /shared, depending on the frequency/size of your file uploads it could become a precarious situation if you fill up the /var partition. So the point is…clean up your merge files! \n\n And this takes us to another thing we can demystify about iControl REST: how do we move/remove files on the file system, or run cli utilities?  Remember that iControl REST is essentially a wrapper for tmsh, so the method needs to be defined there. If you execute run util ? you’ll see a list of commands made available from the system to tmsh. Here is the interesting one for this application: \n\n unix-rm Remove files or directories \n\n So we can remove system files from tmsh and thus iControl REST…huzzah! But what does that look like in the REST call? Another breakdown: \n\n URL: https://bigiphostname/mgmt/tm/util/unix-rm Method: POST Payload: {“command”:”run”, “utilCmdArgs”:”/var/config/rest/downloads/uploaded_file_name” \n\n And in python code, that function looks like this: \n\n \ndef _cleanup_mergefile(host, creds, file):\n requests.packages.urllib3.disable_warnings()\n \n b_url = 'https://%s/mgmt/tm/util/unix-rm' % host\n b = requests.session()\n b.auth = creds\n b.verify = False\n b.headers.update({'Content-Type': 'application/json'})\n \n payload = {}\n payload['command'] = 'run'\n payload['utilCmdArgs'] = '/var/config/rest/downloads/%s' % file\n \n try:\n cleanup = b.post(b_url, json.dumps(payload))\n if cleanup.status_code is not 200:\n print \"Cleanup failed, please check system.\"\n except Exception, e:\n print e \n\n Wrapping Up \n\n So there you have it: a simple python script utilizing iControl REST to upload and merge BIG-IP config files! The full script is available here in the codeshare. What else about iControl REST do you need demystified? Post down in the comments! ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"4395","kudosSumWeight":0,"repliesCount":1,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:286449":{"__typename":"Conversation","id":"conversation:286449","topic":{"__typename":"TkbTopicMessage","uid":286449},"lastPostingActivityTime":"2023-03-07T07:22:15.392-08:00","solved":false},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODY0NDktMTE1MTJpMjkwOTkyOTM4MzQ4REM1MA?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODY0NDktMTE1MTJpMjkwOTkyOTM4MzQ4REM1MA?revision=1","title":"0151T000003d6Y3QAI.png","associationType":"BODY","width":300,"height":104,"altText":null},"TkbTopicMessage:message:286449":{"__typename":"TkbTopicMessage","subject":"Demystifying iControl REST Part 2 - Understanding sub collections and how to use them","conversation":{"__ref":"Conversation:conversation:286449"},"id":"message:286449","revisionNum":1,"uid":286449,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:51154"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":3336},"postTime":"2015-06-23T11:00:00.000-07:00","lastPublishTime":"2015-06-23T11:00:00.000-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" iControl REST. It’s iControl SOAP’s baby brother, introduced back in TMOS version 11.4 as an early access feature but was released fully in version 11.5. \n\n \n\n Several articles on basic usage have been written on iControl REST (see the resources at the bottom of this article) so the intent here isn’t basic use, but rather to demystify some of the finer details of using the API. The first article of this series covered the URI’s role in the API. This second article will cover how the URI path plays a role in how the API functions. \n\n Working with Subcollections \n\n When manipulating F5 configuration items with iControl Rest, subcollections are a powerful tool.  They allow one to manipulate specific items in the subcollection instead of having to manipulate the entire sub collection. Take the pool object for example. If we just query the pool (in this case testpool,) you’ll notice the returned data does not list the pool members \n\n \n#query (via the Chrome advanced REST client using Authorization & Content-Type headers:)\nhttps://172.16.44.128/mgmt/tm/ltm/pool/~Common~testpool\n#query (via curl:)\ncurl -k -u admin:admin https://172.16.44.128/mgmt/tm/ltm/pool/~Common~testpool\n\n#response:\n{\nkind: \"tm:ltm:pool:poolstate\"\nname: \"testpool\"\nfullPath: \"testpool\"\ngeneration: 1\nselfLink: \"https://localhost/mgmt/tm/ltm/pool/testpool?ver=11.6.0\"\nallowNat: \"yes\"\nallowSnat: \"yes\"\nignorePersistedWeight: \"disabled\"\nipTosToClient: \"pass-through\"\nipTosToServer: \"pass-through\"\nlinkQosToClient: \"pass-through\"\nlinkQosToServer: \"pass-through\"\nloadBalancingMode: \"round-robin\"\nminActiveMembers: 0\nminUpMembers: 0\nminUpMembersAction: \"failover\"\nminUpMembersChecking: \"disabled\"\nqueueDepthLimit: 0\nqueueOnConnectionLimit: \"disabled\"\nqueueTimeLimit: 0\nreselectTries: 0\nserviceDownAction: \"none\"\nslowRampTime: 10\nmembersReference: {\nlink: \"https://localhost/mgmt/tm/ltm/pool/~Common~testpool/members?ver=11.6.0\"\nisSubcollection: true\n}-\n}\n \n\n Notice the isSubcollection: true for the membersReference? This is an indicator that there is a subcollection for the members keyword. If you then query the members for that pool, you will get the subcollection. \n\n \n#query (via the Chrome advanced REST client using Authorization & Content-Type headers:)\nhttps://172.16.44.128/mgmt/tm/ltm/pool/~Common~testpool/members\n#query (via curl:)\ncurl -k -u admin:admin https://172.16.44.128/mgmt/tm/ltm/pool/~Common~testpool/members\n\n#response:\n{\nkind: \"tm:ltm:pool:members:memberscollectionstate\"\nselfLink: \"https://localhost/mgmt/tm/ltm/pool/testpool/members?ver=11.6.0\"\nitems: [4]\n0: {\nkind: \"tm:ltm:pool:members:membersstate\"\nname: \"192.168.103.10:80\"\npartition: \"Common\"\nfullPath: \"/Common/192.168.103.10:80\"\ngeneration: 1\nselfLink: \"https://localhost/mgmt/tm/ltm/pool/testpool/members/~Common~192.168.103.10:80?ver=11.6.0\"\naddress: \"192.168.103.10\"\nconnectionLimit: 0\ndynamicRatio: 1\nephemeral: \"false\"\nfqdn: {\nautopopulate: \"disabled\"\n}-\ninheritProfile: \"enabled\"\nlogging: \"disabled\"\nmonitor: \"default\"\npriorityGroup: 0\nrateLimit: \"disabled\"\nratio: 1\nsession: \"user-enabled\"\nstate: \"unchecked\"\n}\n}\n \n\n You can see that there are four pool members as the item count is four, but I’m only showing one of them here for brevity. The pool members can be added, modified, or deleted at this level. \n\n Add a pool member\n\t URI: https://172.16.44.128/mgmt/tm/ltm/pool/~Common~testpool/members Method: POST  JSON: {“name”:”192.168.103.12:80”} \n\t Modify a pool member\n\t URI: https://172.16.44.128/mgmt/tm/ltm/pool/~Common~testpool/members/~Common~192.168.103.12:80  Method: PUT  JSON: {“name”:”192.168.103.12:80”,”connectionLimit”:”50”} \n\t Delete a pool member\n\t URI: https://172.16.44.128/mgmt/tm/ltm/pool/~Common~testpool/members/~Common~192.168.103.12:80 Method: DELETE JSON: none (an error will trigger if you send any data) \n\t \n\n So for subcollections like pool members, adding and deleting is pretty straight forward. Unfortunately, not all lists of configuration items are treated as subcollections. For example, take the data group. You can see for the data group testdb below, the records are not a subcollection. \n\n \n{\nkind: \"tm:ltm:data-group:internal:internalstate\"\nname: \"testdb\"\nfullPath: \"testdb\"\ngeneration: 1\nselfLink: \"https://localhost/mgmt/tm/ltm/data-group/internal/testdb?ver=11.6.0\"\ntype: \"string\"\nrecords: [3]\n0: {\nname: \"a\"\ndata: \"one\"\n}-\n1: {\nname: \"b\"\ndata: \"two\"\n}-\n2: {\nname: \"c\"\n}-\n-\n} \n\n Because this is not a subcollection, any modifications to the records of this object are treated as complete replacements. Thus, this request to add a record (d) to the list: \n\n URL: https://172.16.44.128/mgmt/tm/ltm/data-group/internal/testdb Method: PUT JSON: {“records” : [ { “name”: “d” } ] } \n\n will result in a data group with only 1 entry (d)! If one wanted to add (d) to the data group, one would have to issue the same request above, but with complete JSON data representing the original records PLUS the new record. The same goes if you want to delete a record. You need to submit all the records in JSON format sans the one you wish to delete via the PUT request above.  \n\n Note: Whereas it's true an update to the records attribute requires a full replacement, it IS possible to update individual records by using the options query parameter instead of updating the records attribute. For details, see the update section of this article. \n\n Thus, to modify items that are not subcollections, one would have to issue a get and parse the existing items into a list. Then one would need to modify the list as desired (adding and/or deleting items), and then issue a PUT to the object URI with the modified list as the json data. A python example of doing just that is shown below. This script grabs the records for the MyNetworks data group, adds three new networks to it, then removes those three networks to return it to its original state. \n\n \n__author__ = 'rahm'\n\ndef get_dg(rq, url, dg_details):\n dg = rq.get('%s/ltm/data-group/%s/%s' % (url, dg_details[0], dg_details[1])).json()\n return dg\n\ndef extend_dg(rq, url, dg_details, additional_records):\n dg = rq.get('%s/ltm/data-group/%s/%s' % (url, dg_details[0], dg_details[1])).json()\n\n current_records = dg['records']\n new_records = []\n for record in current_records:\n nr = [ {'name': record['name']}]\n new_records.extend(nr)\n for record in additional_records:\n nr = [ {'name': record}]\n new_records.extend(nr)\n\n payload = {}\n payload['records'] = new_records\n rq.put('%s/ltm/data-group/%s/%s' % (url, dg_details[0], dg_details[1]), json.dumps(payload))\n\ndef contract_dg(rq, url, dg_details, removal_records):\n dg = rq.get('%s/ltm/data-group/%s/%s' % (url, dg_details[0], dg_details[1])).json()\n\n new_records = []\n for record in removal_records:\n nr = [ {'name': record}]\n new_records.extend(nr)\n\n current_records = dg['records']\n new_records = [x for x in current_records if x not in new_records]\n\n payload = {}\n payload['records'] = new_records\n rq.put('%s/ltm/data-group/%s/%s' % (url, dg_details[0], dg_details[1]), json.dumps(payload))\n\nif __name__ == \"__main__\":\n import requests, json\n\n b = requests.session()\n b.auth = ('admin', 'admin')\n b.verify = False\n b.headers.update({'Content-Type' : 'application/json'})\n\n b_url_base = 'https://172.16.44.128/mgmt/tm'\n\n dg_details = ['internal', 'myNetworks']\n net_changes = ['3.0.0.0/8', '4.0.0.0/8']\n\n print \"\\nExisting Records for %s Data-Group:\\n\\t%s\" % (dg_details[1], get_dg(b, b_url_base, dg_details)['records'])\n extend_dg(b, b_url_base, dg_details, net_changes)\n print \"\\nUpdated Records for %s Data-Group:\\n\\t%s\" % (dg_details[1], get_dg(b, b_url_base, dg_details)['records'])\n contract_dg(b, b_url_base, dg_details, net_changes)\n print \"\\nUpdated Records for %s Data-Group:\\n\\t%s\" % (dg_details[1], get_dg(b, b_url_base, dg_details)['records']) \n\n When running this against my lab BIG-IP, I get this output on my console \n\n \nExisting Records for myNetworks Data-Group:\n[{u'name': u'1.0.0.0/8'}, {u'name': u'2.0.0.0/8'}]\n\nUpdated Records for myNetworks Data-Group:\n[{u'name': u'1.0.0.0/8'}, {u'name': u'2.0.0.0/8'}, {u'name': u'3.0.0.0/8'}, {u'name': u'4.0.0.0/8'}]\n\nUpdated Records for myNetworks Data-Group:\n[{u'name': u'1.0.0.0/8'}, {u'name': u'2.0.0.0/8'}]\n\nProcess finished with exit code 0\n \n\n Hopefully this has been helpful in showing the power of subcollections and the necessary steps to update objects like data-groups that are not. Much thanks again to Pat Chang for the bulk of the content in this article Next up: Query Parameters and Options. ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"8683","kudosSumWeight":2,"repliesCount":5,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODY0NDktMTE1MTJpMjkwOTkyOTM4MzQ4REM1MA?revision=1\"}"}}],"totalCount":1,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:286957":{"__typename":"Conversation","id":"conversation:286957","topic":{"__typename":"TkbTopicMessage","uid":286957},"lastPostingActivityTime":"2021-07-22T15:01:57.000-07:00","solved":false},"TkbTopicMessage:message:286957":{"__typename":"TkbTopicMessage","subject":"Demystifying iControl REST Part 3 - How to pass query parameters and tmsh options","conversation":{"__ref":"Conversation:conversation:286957"},"id":"message:286957","revisionNum":1,"uid":286957,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:51154"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":9364},"postTime":"2015-07-09T12:00:00.000-07:00","lastPublishTime":"2015-07-09T12:00:00.000-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" iControl REST. It’s iControl SOAP’s baby, brother, introduced back in TMOS version 11.4 as an early access feature but released fully in version 11.5. \n\n Several articles on basic usage have been written on iControl REST (see the resources at the bottom of this article) so the intent here isn’t basic use, but rather to demystify some of the finer details of using the API. The first article covered URI specifics, the second article discussed subcollections, and this third article will cover query parameters. \n\n Query Parameter Definitions \n\n F5 has documented a number of query parameters that can be passed into iControl ReST calls in order to modify their behavior. The first set follows the OData (open data protocol) standard. The filter parameter also supports several operators. \n\n $filter $select $skip $top \n\n Yes, the dollar sign is important and necessary on these parameters. The operators you can use on these parameters are below. Note that the eq operator can only be used with the filter. \n\n eq - equal ne - not equal lt - less than le - less than or equal gt - greater than ge - greater than or equal Logical Operators:\n and or not \n \n\n Beyond the OData parameters, there are a few custom parameters as well. \n\n expandSubcollections - allows you to get the subcollection data in the initial request for objects that have subcollections. options - allows you to add arguments to the tmsh equivalent command. An example will be shown below. ver - This is for the specific TMOS version. Setting this parameter guarantees consistent behavior through code upgrades. Please note that the JSON return data for a number of calls has changed between the initial release in 11.5.0 and the current release. No items have been removed, but key/value pairs in the output have been added. \n\n Note the lack of a dollar sign on the custom parameters. \n\n Example #1 - Filter \n\n Now that we have the parameters and operators defined, let’s take a look at some examples. First, we’ll take a look at the $filter parameter. If you want to limit your results to a particular partition, your URL will look something like this: \n\n \nhttps://172.16.44.128/mgmt/tm/ltm/pool?$filter=partition eq staging\nhttps://172.16.44.128/mgmt/tm/ltm/pool?$filter=partition%20eq%20staging\nhttps://172.16.44.128/mgmt/tm/ltm/pool?$filter=partition+eq+staging \n\n As long as your client tool supports it, any of these formats will work, but the resulting selfLink reflects the latter format: \n\n   \n\n selfLink: \"https://localhost/mgmt/tm/ltm/pool?$filter=partition+eq+staging \n\n Example #2 - Select \n\n I didn’t post the return data from example 1 because it’s a lot of data, even for a small set of returned results. Most of it is all the fields in a pool that are there and important, but default and not of as immediate importance as others. This is where the $select parameter comes in. If you just want to take a look at the name of the pool and say the load balancing mode, your URL will look like this (still filtering for the staging partition:) \n\n \nhttps://172.16.44.128/mgmt/tm/ltm/pool?$filter=partition+eq+staging&$select=name,loadBalancingMode \n\n This results in a smaller subset of data limited to the fields we “selected\" \n\n \nitems: [5]\n0: {\nname: \"sp1\"\nloadBalancingMode: \"round-robin\"\n}-\n1: {\nname: \"sp2\"\nloadBalancingMode: \"round-robin\"\n}-\n2: {\nname: \"sp3\"\nloadBalancingMode: \"round-robin\"\n} \n\n Example #3 - Top & Skip \n\n For larger sets of data, you can page through the objects in chunks with $top and $skip. If $skip is not specified when $top is used, it behaves as though set to 0. Please note, however, that paging is restricted to collections and sub collections, so whereas this would work to page through the defined data groups, it would not work to page through the records of a data group. Let’s add the top parameter to our previous URL: \n\n \nhttps://172.16.44.128/mgmt/tm/ltm/pool?$filter=partition eq staging&$select=name,loadBalancingMode&$top=2\n\n#Results\n{\nkind: \"tm:ltm:pool:poolcollectionstate\"\nselfLink: \"https://localhost/mgmt/tm/ltm/pool?$filter=partition+eq+staging&$select=name%2CloadBalancingMode&$top=2&ver=12.0.0\"\ncurrentItemCount: 2\nitemsPerPage: 2\npageIndex: 1\nstartIndex: 1\ntotalItems: 5\ntotalPages: 3\nitems: [2]\n0:  {\nname: \"sp1\"\nloadBalancingMode: \"round-robin\"\n}\n-\n1:  {\nname: \"sp2\"\nloadBalancingMode: \"round-robin\"\n}\n-\n-\nnextLink: \"https://localhost/mgmt/tm/ltm/pool?$filter=partition+eq+staging&$select=name%2CloadBalancingMode&$top=2&$skip=2&ver=12.0.0\"\n \n\n So we got the same data back as before, only 2 items instead of the original 5, as well as some additional fields that weren’t there previously. Note that once $top is used, the key/value pairs “nextLink”, “currentItems”, and “totalItems” are added to the response. “nextLink” is the URI that will grab the next $top number of results from the query. If you parse this value and use it (once you have replaced the localhost with your actual host information), you will not have to perform any paging calculations. “currentItems” tells you how many items have been returned in the current call. If this value is less than $top, then you know you have reached the end of the items. “totalItems” tells you how many items would be returned if one did not page using $top. \n\n Example #4 - Options \n\n For this next example, we’ll start with tmsh. If you want to get the connections on the BIG-IP, you type “tmsh show sys conn” at the command line. This can be a very large set of data, however, so there are options on the command line to narrow this down, like cs-client-addr, cs-client-port, and so on. So a narrowed down request at the command line would look like “tmsh show sys conn cs-client-addr 10.0.0.1 cs-client-port 62223.” To translate this command to an API request, you need to use the options parameter \n\n \nhttps://172.16.44.128/mgmt/tm/sys/connection?options=cs-server-addr+192.168.102.50+cs-server-port+80\n\n#Results\n{\nkind: \"tm:sys:connection:connectionstats\"\nselfLink: \"https://localhost/mgmt/tm/sys/connection?options=cs-server-addr+192.168.102.50+cs-server-port+80&ver=11.6.0\"\napiRawValues: {\napiAnonymous: \"Sys::Connections 192.168.102.5:57359 192.168.102.50:80 192.168.102.5:57359 192.168.103.11:8080 tcp 2 (tmm: 1) none Total records returned: 1 \"\n}-\n}\n \n\n Example #5 - Expanding Subcollections \n\n For our final example, we’ll use the expandSubcollections parameter. This is useful for querying objects like pools that have subcollections. Without the parameter specified, the pool data is returned with the specification that pool members is a subcollection, but doesn’t return the set of pool members. By providing the parameter, the pool members are returned along with the pool definition (only first one shown for brevity.) \n\n \nhttps://172.16.44.128/mgmt/tm/ltm/pool/testpool?expandSubcollections=true\n\n#Results\n{\nkind: \"tm:ltm:pool:poolstate\"\nname: \"testpool\"\nfullPath: \"testpool\"\ngeneration: 1\nselfLink: \"https://localhost/mgmt/tm/ltm/pool/testpool?expandSubcollections=true&ver=11.6.0\"\nallowNat: \"yes\"\nallowSnat: \"yes\"\nignorePersistedWeight: \"disabled\"\nipTosToClient: \"pass-through\"\nipTosToServer: \"pass-through\"\nlinkQosToClient: \"pass-through\"\nlinkQosToServer: \"pass-through\"\nloadBalancingMode: \"round-robin\"\nminActiveMembers: 0\nminUpMembers: 0\nminUpMembersAction: \"failover\"\nminUpMembersChecking: \"disabled\"\nqueueDepthLimit: 0\nqueueOnConnectionLimit: \"disabled\"\nqueueTimeLimit: 0\nreselectTries: 0\nserviceDownAction: \"none\"\nslowRampTime: 10\nmembersReference: {\nlink: \"https://localhost/mgmt/tm/ltm/pool/~Common~testpool/members?ver=11.6.0\"\nisSubcollection: true\nitems: [7]\n0: {\nkind: \"tm:ltm:pool:members:membersstate\"\nname: \"192.168.103.10:80\"\npartition: \"Common\"\nfullPath: \"/Common/192.168.103.10:80\"\ngeneration: 1\nselfLink: \"https://localhost/mgmt/tm/ltm/pool/~Common~testpool/members/~Common~192.168.103.10:80?ver=11.6.0\"\naddress: \"192.168.103.10\"\nconnectionLimit: 0\ndynamicRatio: 1\nephemeral: \"false\"\nfqdn: {\nautopopulate: \"disabled\"\n}\n... \n\n Example #6 - Careful! Select Revisited \n\n If you want to select just the name and address from the pool members in the previous example, it's not as simple as adding the $select=name,address to that query. Remember from the earlier article about your object/component/sub-component tiers. Instead, you need to specify the members subcollection in the URL, then attach your select parameter. \n\n \nhttps://172.16.44.128/mgmt/tm/ltm/pool/testpool/members?$select=name,address\n#Results\n{\nkind: \"tm:ltm:pool:members:memberscollectionstate\"\nselfLink: \"https://localhost/mgmt/tm/ltm/pool/testpool/members?$select=name%2Caddress&ver=11.6.0\"\nitems: [7]\n0: {\nname: \"192.168.103.10:80\"\naddress: \"192.168.103.10\"\n}-\n1: {\nname: \"192.168.103.10:8080\"\naddress: \"192.168.103.10\"\n}-\n2: {\nname: \"192.168.103.11:80\"\naddress: \"192.168.103.11\"\n}\n... \n\n A Whiteboard Wednesday Shout Out to iControl REST \n\n I’ve summarized a lot of what was covered in this article in the following Whiteboard Wednesday video. Enjoy! \n\n ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"9076","kudosSumWeight":2,"repliesCount":26,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:286597":{"__typename":"Conversation","id":"conversation:286597","topic":{"__typename":"TkbTopicMessage","uid":286597},"lastPostingActivityTime":"2016-10-28T22:26:26.000-07:00","solved":false},"TkbTopicMessage:message:286597":{"__typename":"TkbTopicMessage","subject":"Demystifying iControl REST Part 4: Working with JSON Data","conversation":{"__ref":"Conversation:conversation:286597"},"id":"message:286597","revisionNum":1,"uid":286597,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:51154"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":2215},"postTime":"2015-11-10T03:00:00.000-08:00","lastPublishTime":"2015-11-10T03:00:00.000-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" iControl REST. It’s iControl SOAP’s baby, brother, introduced back in TMOS version 11.4 as an early access feature but released fully in version 11.5. \n\n Several articles on basic usage have been written on iControl REST so the intent here isn’t basic use, but rather to demystify some of the finer details of using the API. This article will cover the details on how to work with the json data format used by iControl REST. \n\n Formatting returned data for inspection \n\n When first working with iControl REST, you might simply need to display the data queried with a browser REST client, or with curl from the command line. However, that doesn’t look too pretty by default: \n\n \n[root@localhost:Active:Standalone] config # curl -sk -u admin:admin https://172.16.44.15/mgmt/tm/ltm/rule/linkinfo\n{\"kind\":\"tm:ltm:rule:rulestate\",\"name\":\"linkinfo\",\"fullPath\":\"linkinfo\",\"generation\":1,\"selfLink\":\"https://localhost/mgmt/tm/ltm/rule/linkinfo?ver=12.0.0\",\"apiAnonymous\":\"when FLOW_INIT {\\n \\tlog local0. \\\"Lasthop ID: [LINK::lasthop id], Type: [LINK::lasthop type], Name: [LINK::lasthop name].\\\"\\n \\tlog local0. \\\"Nexthop ID: [LINK::nexthop id], Type: [LINK::nexthop type], Name: [LINK::nexthop name].\\\"\\n}\"}[root@localhost:Active:Standalone] \n\n That’s where the following formatting options come into play. There are examples for perl and php floating around as well, but I’ve yet to make them work locally on the BIG-IP, so I haven’t included them here to avoid confusion. \n\n python -m json.tool (all versions) json-format (12.0+) jq . (confirmed in 12.0, but if not in 11.x versions, the executable can be installed and referenced accordingly) \n\n Using each of these, results in a nice formatting of the data: \n\n \n[root@localhost:Active:Standalone] config # curl -sk -u admin:admin \\\nhttps://172.16.44.15/mgmt/tm/ltm/rule/linkinfo | python -m json.tool\n{\n \"apiAnonymous\": \"when FLOW_INIT {\\n \\tlog local0. \\\"Lasthop ID: [LINK::lasthop id], Type: [LINK::lasthop type], Name: [LINK::lasthop name].\\\"\\n \\tlog local0. \\\"Nexthop ID: [LINK::nexthop id], Type: [LINK::nexthop type], Name: [LINK::nexthop name].\\\"\\n}\",\n \"fullPath\": \"linkinfo\",\n \"generation\": 1,\n \"kind\": \"tm:ltm:rule:rulestate\",\n \"name\": \"linkinfo\",\n \"selfLink\": \"https://localhost/mgmt/tm/ltm/rule/linkinfo?ver=12.0.0\"\n}\n[root@localhost:Active:Standalone] config # curl -sk -u admin:admin \\\nhttps://172.16.44.15/mgmt/tm/ltm/rule/linkinfo | json-format\n{\n \"kind\": \"tm:ltm:rule:rulestate\",\n \"name\": \"linkinfo\",\n \"fullPath\": \"linkinfo\",\n \"generation\": 1,\n \"selfLink\": \"https://localhost/mgmt/tm/ltm/rule/linkinfo?ver\\u003d12.0.0\",\n \"apiAnonymous\": \"when FLOW_INIT {\\n \\tlog local0. \\\"Lasthop ID: [LINK::lasthop id], Type: [LINK::lasthop type], Name: [LINK::lasthop name].\\\"\\n \\tlog local0. \\\"Nexthop ID: [LINK::nexthop id], Type: [LINK::nexthop type], Name: [LINK::nexthop name].\\\"\\n}\"\n}\n[root@localhost:Active:Standalone] config # curl -sk -u admin:admin \\\nhttps://172.16.44.15/mgmt/tm/ltm/rule/linkinfo | jq .\n{\n \"kind\": \"tm:ltm:rule:rulestate\",\n \"name\": \"linkinfo\",\n \"fullPath\": \"linkinfo\",\n \"generation\": 1,\n \"selfLink\": \"https://localhost/mgmt/tm/ltm/rule/linkinfo?ver=12.0.0\",\n \"apiAnonymous\": \"when FLOW_INIT {\\n \\tlog local0. \\\"Lasthop ID: [LINK::lasthop id], Type: [LINK::lasthop type], Name: [LINK::lasthop name].\\\"\\n \\tlog local0. \\\"Nexthop ID: [LINK::nexthop id], Type: [LINK::nexthop type], Name: [LINK::nexthop name].\\\"\\n}\"\n} \n\n If you are on the BIG-IP command line, you will notice that with jq, you also get pretty printing with color, clarifying the key/value pairs. Also with jq, you can return specific fields in the data, see this article for more details. Of course, you might want to do more than just query data. You might also want to use the REST API to create or modify objects as well. You will need to create the POST/PUT/PATCH payload for this, and it should be in JSON format as well. You don’t need to fully populate an object’s fields to successfully submit and create/modify it, you just need to make sure the required fields are present. That changes for each object and for the nature of the changes you are making to an object. Follow the tmsh documentation’s lead for this, either from the reference guide or from interrogating objects in the tmsh shell. For example, to create a pool, you just need to supply the pool name. \n\n \ncurl -sk -u admin:admin https://172.16.44.15/mgmt/tm/ltm/pool \\\n -H 'Content-Type: application/json' \\\n -X POST \\\n -d '{\"name\":\"myNewPool\"}' \n\n Interrogating returned data programmatically \n\n So browser tools and curl are great, but that’s a lot of typing if you are going to be using the REST API frequently to perform tasks. This is where a programming language of your choice comes into play. By moving all of your work into code, you are automating the tedium of typing (and remembering) all the nuances of working with the interface. \n\n My language of choice is python. For one, it has a nice interpreter shell where you can code line by line and see results. Python’s json module makes it really easy to interrogate data returned from the BIG-IP, and to package data for presenting to the BIG-IP in an object type of choice. Let’s start the shell by typing “python” at the cli and getting the environment ready to make queries. \n\n \n>>> import requests, json\n>>> b = requests.session()\n>>> b.auth = ('admin', 'admin')\n>>> b.verify = False\n>>> b.headers.update({'Content-TYpe':'application/json'})\n>>> b_url_base = 'https://172.16.44.15/mgmt/tm'\n>>> dg_details = ['internal', 'images'] \n\n Now we can make a query to the API, substituting the base url (https://172.16.44.15/mgmt/tm,) the data-group type (internal,) and the name (images.) The requests module object includes the payload and headers, methods, etc, from http, so we need to append another method to interrogate the payload. Let’s start with .text. \n\n \n>>> dg1 = b.get('%s/ltm/data-group/%s/%s' % (b_url_base, dg_details[0], dg_details[1])).text\n>>> type(dg1)\n<type 'unicode'> \n\n You can see that the .text method results in a unicode string: \n\n \nu'{\"kind\":\"tm:ltm:data-group:internal:internalstate\",\"name\":\"images\",\"fullPath\":\"images\",\"generation\":1,\"selfLink\":\"https://localhost/mgmt/tm/ltm/data-group/internal/images?ver=12.0.0\",\"type\":\"string\",\"records\":[{\"name\":\".bmp\"},{\"name\":\".gif\"},{\"name\":\".jpg\"}]}'\n \n\n This is helpful to see what your return data is, but not very helpful programmatically. If you try to tickle the kind attribute on a string, you’ll get an error. But by switching from the .text method to .json(), it’ll convert the json data to the native python dictionary object. \n\n \n>>> dg2 = b.get('%s/ltm/data-group/%s/%s' % (b_url_base, dg_details[0], dg_details[1])).json()\n>>> type(dg)\n<type 'dict'>\n>>> dg2\n{u'kind': u'tm:ltm:data-group:internal:internalstate', u'name': u'images', u'generation': 1, u'records': [{u'name': u'.bmp'}, {u'name': u'.gif'}, {u'name': u'.jpg'}], u'fullPath': u'images', u'type': u'string', u'selfLink': u'https://localhost/mgmt/tm/ltm/data-group/internal/images?ver=12.0.0'}\n \n\n Now that the data is in a dictionary, you can tickle the attributes of the dg2 object. Let’s print out the records from that dictionary: \n\n \n>>> dg2 = b.get('%s/ltm/data-group/%s/%s' % (b_url_base, dg_details[0], dg_details[1])).json()\n>>> for record in dg2['records']:\n... print record['name']\n...\n.bmp\n.gif\n.jpg\n \n\n So that’s great for return data. But what about data you need to push to the BIG-IP? Well, that’s also easy! Let’s step through this in the python shell: \n\n \n>>> dg3 = {}\n>>> dg3['name'] = 'images2'\n>>> dg3['type'] = 'string'\n>>> records = ['.png', '.bmp', '.jpg']\n>>> record_obj = []\n>>> for record in records:\n... nr = [ {'name': record}]\n... record_obj.extend(nr)\n...\n>>> dg3['records'] = record_obj\n>>> dg3\n{'records': [{'name': '.png'}, {'name': '.bmp'}, {'name': '.jpg'}], 'type': 'string', 'name': 'images2'}\n>>> b.post('%s/ltm/data-group/internal' % b_url_base, json.dumps(dg3)).json()\n{u'kind': u'tm:ltm:data-group:internal:internalstate', u'name': u'images2', u'generation': 330, u'records': [{u'name': u'.bmp'}, {u'name': u'.jpg'}, {u'name': u'.png'}], u'fullPath': u'images2', u'type': u'string', u'selfLink': u'https://localhost/mgmt/tm/ltm/data-group/internal/images2?ver=12.0.0'} \n\n Start by creating an empty dictionary and assigning to dg3. Then populate the name and type keys. For the records, iterate through the image type list, extending the records obj to add to the dictionary. After verifying the dictionary is populated correctly, the post can be issued. Notice in that command the json.dumps(dg3)? That is where python converts the native dictionary type to json data before submitting the payload. I added the .json() on the end to verify the images2 data-group was actually created. \n\n Conclusion \n\n There are a lot of ways to work with json data. This article covered a couple approaches you can use in your journey to world domination. What’s your approach? Any tools on your tool belt you’d like to share with the community? Drop a comment below! ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"9306","kudosSumWeight":1,"repliesCount":4,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"CachedAsset:text:en_US-components/community/Navbar-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/community/Navbar-1740415735000","value":{"community":"Community Home","inbox":"Inbox","manageContent":"Manage Content","tos":"Terms of Service","forgotPassword":"Forgot Password","themeEditor":"Theme Editor","edit":"Edit Navigation Bar","skipContent":"Skip to content","migrated-link-9":"Groups","migrated-link-7":"Technical Articles","migrated-link-8":"DevCentral News","migrated-link-1":"Technical Forum","migrated-link-10":"Community Groups","migrated-link-2":"Water Cooler","migrated-link-11":"F5 Groups","Common-external-link":"How Do I...?","migrated-link-0":"Forums","article-series":"Article Series","migrated-link-5":"Community Articles","migrated-link-6":"Articles","security-insights":"Security Insights","migrated-link-3":"CrowdSRC","migrated-link-4":"CodeShare","migrated-link-12":"Events","migrated-link-13":"Suggestions"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarHamburgerDropdown-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarHamburgerDropdown-1740415735000","value":{"hamburgerLabel":"Side Menu"},"localOverride":false},"CachedAsset:text:en_US-components/community/BrandLogo-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/community/BrandLogo-1740415735000","value":{"logoAlt":"Khoros","themeLogoAlt":"Brand Logo"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarTextLinks-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarTextLinks-1740415735000","value":{"more":"More"},"localOverride":false},"CachedAsset:text:en_US-components/authentication/AuthenticationLink-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/authentication/AuthenticationLink-1740415735000","value":{"title.login":"Sign In","title.registration":"Register","title.forgotPassword":"Forgot Password","title.multiAuthLogin":"Sign In"},"localOverride":false},"CachedAsset:text:en_US-components/nodes/NodeLink-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/nodes/NodeLink-1740415735000","value":{"place":"Place {name}"},"localOverride":false},"CachedAsset:text:en_US-components/tags/TagSubscriptionAction-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/tags/TagSubscriptionAction-1740415735000","value":{"success.follow.title":"Following Tag","success.unfollow.title":"Unfollowed Tag","success.follow.message.followAcrossCommunity":"You will be notified when this tag is used anywhere across the community","success.unfollowtag.message":"You will no longer be notified when this tag is used anywhere in this place","success.unfollowtagAcrossCommunity.message":"You will no longer be notified when this tag is used anywhere across the community","unexpected.error.title":"Error - Action Failed","unexpected.error.message":"An unidentified problem occurred during the action you took. Please try again later.","buttonTitle":"{isSubscribed, select, true {Unfollow} false {Follow} other{}}","unfollow":"Unfollow"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageListTabs-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageListTabs-1740415735000","value":{"mostKudoed":"{value, select, IDEA {Most Votes} other {Most Likes}}","mostReplies":"Most Replies","mostViewed":"Most Viewed","newest":"{value, select, IDEA {Newest Ideas} OCCASION {Newest Events} other {Newest Topics}}","newestOccasions":"Newest Events","mostRecent":"Most Recent","noReplies":"No Replies Yet","noSolutions":"No Solutions Yet","solutions":"Solutions","mostRecentUserContent":"Most Recent","trending":"Trending","draft":"Drafts","spam":"Spam","abuse":"Abuse","moderation":"Moderation","tags":"Tags","PAST":"Past","UPCOMING":"Upcoming","sortBymostRecent":"Sort By Most Recent","sortBymostRecentUserContent":"Sort By Most Recent","sortBymostKudoed":"Sort By Most Likes","sortBymostReplies":"Sort By Most Replies","sortBymostViewed":"Sort By Most Viewed","sortBynewest":"Sort By Newest Topics","sortBynewestOccasions":"Sort By Newest Events","otherTabs":" Messages list in the {tab} for {conversationStyle}","guides":"Guides","archives":"Archives"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/QueryHandler-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/QueryHandler-1740415735000","value":{"title":"Query Handler"},"localOverride":false},"Category:category:top":{"__typename":"Category","id":"category:top","nodeType":"category"},"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarDropdownToggle-1740415735000","value":{"ariaLabelClosed":"Press the down arrow to open the menu"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/OverflowNav-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/OverflowNav-1740415735000","value":{"toggleText":"More"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageView/MessageViewInline-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageView/MessageViewInline-1740415735000","value":{"bylineAuthor":"{bylineAuthor}","bylineBoard":"{bylineBoard}","anonymous":"Anonymous","place":"Place {bylineBoard}","gotoParent":"Go to parent {name}"},"localOverride":false},"CachedAsset:text:en_US-components/customComponent/CustomComponent-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/customComponent/CustomComponent-1740415735000","value":{"errorMessage":"Error rendering component id: {customComponentId}","bannerTitle":"Video provider requires cookies to play the video. Accept to continue or {url} it directly on the provider's site.","buttonTitle":"Accept","urlText":"watch"},"localOverride":false},"CachedAsset:text:en_US-components/users/UserLink-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/users/UserLink-1740415735000","value":{"authorName":"View Profile: {author}","anonymous":"Anonymous"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageSubject-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageSubject-1740415735000","value":{"noSubject":"(no subject)"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageBody-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageBody-1740415735000","value":{"showMessageBody":"Show More","mentionsErrorTitle":"{mentionsType, select, board {Board} user {User} message {Message} other {}} No Longer Available","mentionsErrorMessage":"The {mentionsType} you are trying to view has been removed from the community.","videoProcessing":"Video is being processed. Please try again in a few minutes.","bannerTitle":"Video provider requires cookies to play the video. Accept to continue or {url} it directly on the provider's site.","buttonTitle":"Accept","urlText":"watch"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageTime-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageTime-1740415735000","value":{"postTime":"Published: {time}","lastPublishTime":"Last Update: {time}","conversation.lastPostingActivityTime":"Last posting activity time: {time}","conversation.lastPostTime":"Last post time: {time}","moderationData.rejectTime":"Rejected time: {time}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/nodes/NodeIcon-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/nodes/NodeIcon-1740415735000","value":{"contentType":"Content Type {style, select, FORUM {Forum} BLOG {Blog} TKB {Knowledge Base} IDEA {Ideas} OCCASION {Events} other {}} icon"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageUnreadCount-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageUnreadCount-1740415735000","value":{"unread":"{count} unread","comments":"{count, plural, one { unread comment} other{ unread comments}}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageViewCount-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageViewCount-1740415735000","value":{"textTitle":"{count, plural,one {View} other{Views}}","views":"{count, plural, one{View} other{Views}}"},"localOverride":false},"CachedAsset:text:en_US-components/kudos/KudosCount-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/kudos/KudosCount-1740415735000","value":{"textTitle":"{count, plural,one {{messageType, select, IDEA{Vote} other{Like}}} other{{messageType, select, IDEA{Votes} other{Likes}}}}","likes":"{count, plural, one{like} other{likes}}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageRepliesCount-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageRepliesCount-1740415735000","value":{"textTitle":"{count, plural,one {{conversationStyle, select, IDEA{Comment} OCCASION{Comment} other{Reply}}} other{{conversationStyle, select, IDEA{Comments} OCCASION{Comments} other{Replies}}}}","comments":"{count, plural, one{Comment} other{Comments}}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/users/UserAvatar-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/users/UserAvatar-1740415735000","value":{"altText":"{login}'s avatar","altTextGeneric":"User's avatar"},"localOverride":false}}}},"page":"/tags/TagPage/TagPage","query":{"tagName":"series-demystifying-icontrol-rest"},"buildId":"q_bLpq2mflH0BeZigxpj6","runtimeConfig":{"buildInformationVisible":false,"logLevelApp":"info","logLevelMetrics":"info","openTelemetryClientEnabled":false,"openTelemetryConfigName":"f5","openTelemetryServiceVersion":"25.2.0","openTelemetryUniverse":"prod","openTelemetryCollector":"http://localhost:4318","openTelemetryRouteChangeAllowedTime":"5000","apolloDevToolsEnabled":false,"inboxMuteWipFeatureEnabled":false},"isFallback":false,"isExperimentalCompile":false,"dynamicIds":["./components/customComponent/CustomComponent/CustomComponent.tsx","./components/community/Navbar/NavbarWidget.tsx","./components/community/Breadcrumb/BreadcrumbWidget.tsx","./components/tags/TagsHeaderWidget/TagsHeaderWidget.tsx","./components/messages/MessageListForNodeByRecentActivityWidget/MessageListForNodeByRecentActivityWidget.tsx","./components/tags/TagSubscriptionAction/TagSubscriptionAction.tsx","./components/customComponent/CustomComponentContent/TemplateContent.tsx","../shared/client/components/common/List/ListGroup/ListGroup.tsx","./components/messages/MessageView/MessageView.tsx","./components/messages/MessageView/MessageViewInline/MessageViewInline.tsx","./components/customComponent/CustomComponentContent/HtmlContent.tsx","./components/customComponent/CustomComponentContent/CustomComponentScripts.tsx"],"appGip":true,"scriptLoader":[]}