iApps

113 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/iApps\"}}})":{"__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/iApps\"}}})":{"__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/iApps\"}}})":{"__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\":\"1743097587932\",\"locale\":\"en-US\",\"namespaces\":[\"components/community/NavbarDropdownToggle\"]})":[{"__ref":"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1743097587932"}],"cachedText({\"lastModified\":\"1743097587932\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/common/OverflowNav\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/common/OverflowNav-1743097587932"}],"cachedText({\"lastModified\":\"1743097587932\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageView/MessageViewInline\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageView/MessageViewInline-1743097587932"}],"cachedText({\"lastModified\":\"1743097587932\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/common/Pager/PagerLoadMore\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/common/Pager/PagerLoadMore-1743097587932"}],"cachedText({\"lastModified\":\"1743097587932\",\"locale\":\"en-US\",\"namespaces\":[\"components/customComponent/CustomComponent\"]})":[{"__ref":"CachedAsset:text:en_US-components/customComponent/CustomComponent-1743097587932"}],"cachedText({\"lastModified\":\"1743097587932\",\"locale\":\"en-US\",\"namespaces\":[\"components/users/UserLink\"]})":[{"__ref":"CachedAsset:text:en_US-components/users/UserLink-1743097587932"}],"cachedText({\"lastModified\":\"1743097587932\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageSubject\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageSubject-1743097587932"}],"cachedText({\"lastModified\":\"1743097587932\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageTime\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageTime-1743097587932"}],"cachedText({\"lastModified\":\"1743097587932\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/nodes/NodeIcon\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/nodes/NodeIcon-1743097587932"}],"cachedText({\"lastModified\":\"1743097587932\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageUnreadCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageUnreadCount-1743097587932"}],"cachedText({\"lastModified\":\"1743097587932\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageViewCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageViewCount-1743097587932"}],"cachedText({\"lastModified\":\"1743097587932\",\"locale\":\"en-US\",\"namespaces\":[\"components/kudos/KudosCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/kudos/KudosCount-1743097587932"}],"cachedText({\"lastModified\":\"1743097587932\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageRepliesCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageRepliesCount-1743097587932"}],"cachedText({\"lastModified\":\"1743097587932\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageBody\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageBody-1743097587932"}],"cachedText({\"lastModified\":\"1743097587932\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/users/UserAvatar\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/users/UserAvatar-1743097587932"}]},"CachedAsset:pages-1742464138537":{"__typename":"CachedAsset","id":"pages-1742464138537","value":[{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"HowDoI.GetInvolved.MvpProgram","type":"COMMUNITY","urlPath":"/c/how-do-i/get-involved/mvp-program","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"BlogViewAllPostsPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId/all-posts/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"CasePortalPage","type":"CASE_PORTAL","urlPath":"/caseportal","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"CreateGroupHubPage","type":"GROUP_HUB","urlPath":"/groups/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"CaseViewPage","type":"CASE_DETAILS","urlPath":"/case/:caseId/:caseNumber","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"InboxPage","type":"COMMUNITY","urlPath":"/inbox","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"HowDoI.GetInvolved.AdvocacyProgram","type":"COMMUNITY","urlPath":"/c/how-do-i/get-involved/advocacy-program","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"HowDoI.GetHelp.NonCustomer","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help/non-customer","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"HelpFAQPage","type":"COMMUNITY","urlPath":"/help","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"HowDoI.GetHelp.F5Customer","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help/f5-customer","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"IdeaMessagePage","type":"IDEA_POST","urlPath":"/idea/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"IdeaViewAllIdeasPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/all-ideas/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"LoginPage","type":"USER","urlPath":"/signin","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"BlogPostPage","type":"BLOG","urlPath":"/category/:categoryId/blogs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"HowDoI.GetInvolved","type":"COMMUNITY","urlPath":"/c/how-do-i/get-involved","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"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":1742464138537,"localOverride":null,"page":{"id":"ThemeEditorPage","type":"COMMUNITY","urlPath":"/designer/themes","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"TkbViewAllArticlesPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId/all-articles/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"OccasionEditPage","type":"EVENT","urlPath":"/event/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"OAuthAuthorizationAllowPage","type":"USER","urlPath":"/auth/authorize/allow","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"PageEditorPage","type":"COMMUNITY","urlPath":"/designer/pages","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"PostPage","type":"COMMUNITY","urlPath":"/category/:categoryId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"ForumBoardPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"TkbBoardPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"EventPostPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"UserBadgesPage","type":"COMMUNITY","urlPath":"/users/:login/:userId/badges","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"GroupHubMembershipAction","type":"GROUP_HUB","urlPath":"/membership/join/:nodeId/:membershipType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"MaintenancePage","type":"COMMUNITY","urlPath":"/maintenance","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"IdeaReplyPage","type":"IDEA_REPLY","urlPath":"/idea/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"UserSettingsPage","type":"USER","urlPath":"/mysettings/:userSettingsTab","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"GroupHubsPage","type":"GROUP_HUB","urlPath":"/groups","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"ForumPostPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"OccasionRsvpActionPage","type":"OCCASION","urlPath":"/event/:boardId/:messageSubject/:messageId/rsvp/:responseType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"VerifyUserEmailPage","type":"USER","urlPath":"/verifyemail/:userId/:verifyEmailToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"AllOccasionsPage","type":"OCCASION","urlPath":"/category/:categoryId/events/:boardId/all-events/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"EventBoardPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"TkbReplyPage","type":"TKB_REPLY","urlPath":"/kb/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"IdeaBoardPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"CommunityGuideLinesPage","type":"COMMUNITY","urlPath":"/communityguidelines","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"CaseCreatePage","type":"SALESFORCE_CASE_CREATION","urlPath":"/caseportal/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"TkbEditPage","type":"TKB","urlPath":"/kb/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"ForgotPasswordPage","type":"USER","urlPath":"/forgotpassword","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"IdeaEditPage","type":"IDEA","urlPath":"/idea/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"TagPage","type":"COMMUNITY","urlPath":"/tag/:tagName","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"BlogBoardPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"OccasionMessagePage","type":"OCCASION_TOPIC","urlPath":"/event/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"ManageContentPage","type":"COMMUNITY","urlPath":"/managecontent","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"ClosedMembershipNodeNonMembersPage","type":"GROUP_HUB","urlPath":"/closedgroup/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"HowDoI.GetHelp.Community","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help/community","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"CommunityPage","type":"COMMUNITY","urlPath":"/","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"HowDoI.GetInvolved.ContributeCode","type":"COMMUNITY","urlPath":"/c/how-do-i/get-involved/contribute-code","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"ForumMessagePage","type":"FORUM_TOPIC","urlPath":"/discussions/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"IdeaPostPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"BlogMessagePage","type":"BLOG_ARTICLE","urlPath":"/blog/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"RegistrationPage","type":"USER","urlPath":"/register","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"EditGroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"ForumEditPage","type":"FORUM","urlPath":"/discussions/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"ResetPasswordPage","type":"USER","urlPath":"/resetpassword/:userId/:resetPasswordToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"TkbMessagePage","type":"TKB_ARTICLE","urlPath":"/kb/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"HowDoI.Learn.AboutIrules","type":"COMMUNITY","urlPath":"/c/how-do-i/learn/about-irules","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"BlogEditPage","type":"BLOG","urlPath":"/blog/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"HowDoI.GetHelp.F5Support","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help/f5-support","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"ManageUsersPage","type":"USER","urlPath":"/users/manage/:tab?/:manageUsersTab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"ForumReplyPage","type":"FORUM_REPLY","urlPath":"/discussions/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"PrivacyPolicyPage","type":"COMMUNITY","urlPath":"/privacypolicy","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"NotificationPage","type":"COMMUNITY","urlPath":"/notifications","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"UserPage","type":"USER","urlPath":"/users/:login/:userId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"HealthCheckPage","type":"COMMUNITY","urlPath":"/health","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"OccasionReplyPage","type":"OCCASION_REPLY","urlPath":"/event/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"ManageMembersPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/manage/:tab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"SearchResultsPage","type":"COMMUNITY","urlPath":"/search","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"BlogReplyPage","type":"BLOG_REPLY","urlPath":"/blog/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"GroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"TermsOfServicePage","type":"COMMUNITY","urlPath":"/termsofservice","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"HowDoI.GetHelp","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"HowDoI.GetHelp.SecurityIncident","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help/security-incident","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"CategoryPage","type":"CATEGORY","urlPath":"/category/:categoryId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"ForumViewAllTopicsPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/all-topics/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"TkbPostPage","type":"TKB","urlPath":"/category/:categoryId/kbs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"localOverride":null,"page":{"id":"GroupHubPostPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1742464138537,"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-1742464138143":{"__typename":"CachedAsset","id":"theme:customTheme1-1742464138143","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-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Loading/LoadingDot-1743097587932","value":{"title":"Loading..."},"localOverride":false},"CachedAsset:text:en_US-components/common/EmailVerification-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/common/EmailVerification-1743097587932","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-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-pages/tags/TagPage-1743097587932","value":{"tagPageTitle":"Tag:\"{tagName}\" | {communityTitle}","tagPageForNodeTitle":"Tag:\"{tagName}\" in \"{title}\" | {communityTitle}","name":"Tags Page","tag":"Tag: {tagName}"},"localOverride":false},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bi0zNC0xM2k0MzE3N0Q2NjFBRDg5NDAy\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bi0zNC0xM2k0MzE3N0Q2NjFBRDg5NDAy","mimeType":"image/png"},"Category:category:Articles":{"__typename":"Category","id":"category:Articles","entityType":"CATEGORY","displayId":"Articles","nodeType":"category","depth":1,"title":"Articles","shortTitle":"Articles","parent":{"__ref":"Category:category:top"},"categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:top":{"__typename":"Category","id":"category:top","displayId":"top","nodeType":"category","depth":0,"title":"Top"},"Tkb:board:TechnicalArticles":{"__typename":"Tkb","id":"board:TechnicalArticles","entityType":"TKB","displayId":"TechnicalArticles","nodeType":"board","depth":2,"conversationStyle":"TKB","title":"Technical Articles","description":"F5 SMEs share good practice.","avatar":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bi0zNC0xM2k0MzE3N0Q2NjFBRDg5NDAy\"}"},"profileSettings":{"__typename":"ProfileSettings","language":null},"parent":{"__ref":"Category:category:Articles"},"ancestors":{"__typename":"CoreNodeConnection","edges":[{"__typename":"CoreNodeEdge","node":{"__ref":"Community:community:zihoc95639"}},{"__typename":"CoreNodeEdge","node":{"__ref":"Category:category:Articles"}}]},"userContext":{"__typename":"NodeUserContext","canAddAttachments":false,"canUpdateNode":false,"canPostMessages":false,"isSubscribed":false},"boardPolicies":{"__typename":"BoardPolicies","canPublishArticleOnCreate":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.forums.policy_can_publish_on_create_workflow_action.accessDenied","key":"error.lithium.policies.forums.policy_can_publish_on_create_workflow_action.accessDenied","args":[]}},"canReadNode":{"__typename":"PolicyResult","failureReason":null}},"tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"shortTitle":"Technical Articles","tagPolicies":{"__typename":"TagPolicies","canSubscribeTagOnNode":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.labels.action.corenode.subscribe_labels.allow.accessDenied","key":"error.lithium.policies.labels.action.corenode.subscribe_labels.allow.accessDenied","args":[]}},"canManageTagDashboard":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.labels.action.corenode.admin_labels.allow.accessDenied","key":"error.lithium.policies.labels.action.corenode.admin_labels.allow.accessDenied","args":[]}}}},"CachedAsset:quilt:f5.prod:pages/tags/TagPage:board:TechnicalArticles-1743097589610":{"__typename":"CachedAsset","id":"quilt:f5.prod:pages/tags/TagPage:board:TechnicalArticles-1743097589610","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:1742464053905":{"__typename":"CachedAsset","id":"quiltWrapper:f5.prod:Common:1742464053905","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-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/common/ActionFeedback-1743097587932","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-1742464155653":{"__typename":"CachedAsset","id":"component:custom.widget.Beta_MetaNav-en-1742464155653","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-1742464155653":{"__typename":"CachedAsset","id":"component:custom.widget.Beta_Footer-en-1742464155653","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-1742464155653":{"__typename":"CachedAsset","id":"component:custom.widget.Tag_Manager_Helper-en-1742464155653","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-1742464155653":{"__typename":"CachedAsset","id":"component:custom.widget.Consent_Blackbar-en-1742464155653","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-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/community/Breadcrumb-1743097587932","value":{"navLabel":"Breadcrumbs","dropdown":"Additional parent page navigation"},"localOverride":false},"CachedAsset:text:en_US-components/tags/TagsHeaderWidget-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/tags/TagsHeaderWidget-1743097587932","value":{"tag":"{tagName}","topicsCount":"{count} {count, plural, one {Topic} other {Topics}}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageListForNodeByRecentActivityWidget-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageListForNodeByRecentActivityWidget-1743097587932","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:1743095186784":"Most Recent Updates","title@instance:1704317906837":"Content Feed","title@instance:1743095018194":"Most Recent Updates","title@instance:1702668293472":"Community Feed","title@instance:1743095117047":"Most Recent Updates","title@instance:1704319314827":"Blog Feed","title@instance:1743095235555":"Most Recent Updates","title@instance:1704320290851":"My Contributions","title@instance:1703720491809":"Forum Feed","title@instance:1743095311723":"Most Recent Updates","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}}},"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:339473":{"__typename":"Conversation","id":"conversation:339473","topic":{"__typename":"TkbTopicMessage","uid":339473},"lastPostingActivityTime":"2025-02-05T16:44:02.171-08:00","solved":false},"User:user:216804":{"__typename":"User","uid":216804,"login":"Carl_Brothers","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/images/dS0yMTY4MDQtRDliNTJh?image-coordinates=0%2C89%2C2400%2C2490"},"id":"user:216804"},"TkbTopicMessage:message:339473":{"__typename":"TkbTopicMessage","subject":"Using bash and tmsh to make bulk updates","conversation":{"__ref":"Conversation:conversation:339473"},"id":"message:339473","revisionNum":12,"uid":339473,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:216804"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" Learn how to use bash and tmsh to find any setting across your BIG-IP configuration and make changes quickly. ","introduction":"Lessons learned while writing K000149084","metrics":{"__typename":"MessageMetrics","views":480},"postTime":"2025-02-05T16:44:02.171-08:00","lastPublishTime":"2025-02-05T16:44:02.171-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" How this began \n Customers who may have had AAM/WAM enabled in their BIG-IP systems may be unaware of removal of that entire module and code branch that was done in versions 16 and above. Any BIG-IP systems that had these objects configured, would face problems when upgrading their devices, unless they cleaned the configuration up. \n Since there are many different types of objects (TCP Profiles, Web acceleration Profiles, Acceleration Manager applications, etc), and since iApps were likely the primary deployment method to use AAM/WAM features, I wanted to find a fast way to document and make the changes needed for anyone impacted.       \n   \n Prerequisites \n \n Access to your BIG-IP system via your preferred SSH client. \n Admin credentials for the BIG-IP system. \n Access to the Advanced Shell, aka BASH. \n \n \n Finding specific profiles and settings via the GUI would be rather time consuming, and there is no good way to catalog and inventory what needs to be changed via the GUI. While we can list some items via tmsh, there are better filtering and output formatting tools within bash, plus we can more easily traverse all partitions on the system. I will explain as much about the commands as I know or have discovered in this process. If you consider yourself a bit more advanced, then just skip to the code blocks and enjoy. \n Before taking any of this to a BIG-IP, ensure that you have backed up the configuration and pulled that UCS file off the device. ALWAYS experiment on a test/non production environment before running any of these commands that have modify or delete statements in them. \n \n   \n Scanning All Partitions \n When you launch into tmsh, by default, users with admin permissions will enter into the Common partition. To scan all partitions, you have to get to the root in tmsh. Like most shells, cd / will put you in the root directory. From there, we can use the list command with the recursive option to return objects of interest from all partitions and subfolders (iApps and FAST create subfolders within a partition). Filtering for values of interest and then acting on them is a critical step to ensure we have a proper list for editing later.  \n A challenge to solve is that we need to send two commands into tmsh to get all of the objects across all partitions. Fortunately, tmsh has an option that allows us to send multiple commands via the -c option. The multiple commands need to be inside quotes and separated by a semi-colon. \n   \n List all Virtual Servers on a device \n #this will return a list of all virtual server names \ntmsh -c 'cd /; list ltm virtual recursive one-line' | awk '{print $3}' \n Without the awk command, the entire virtual server config will be returned. In this example, awk is returning the third string/column it sees surrounded by spaces. Because we have every virtual server config, we can search for specific elements of interest using grep to either include or exclude based on what we seek. \n   \n List all Virtual Servers on a device using the tcp profile \n Before you build a fancy grep string, only to figure out the value is not returned by the command because it is an implicit default value, add the all-properties option before the one-line option. In this example, we will list all virtual servers where the default tcp profile is being used for client-side (downstream in NGINX) and server side (upstream in NGINX). \n #Find Virtual Servers using the default tcp profile on client side and server side \ntmsh -c 'cd /; list ltm virtual recursive all-properties one-line' | grep -E \"Common/tcp { context all }\" |awk '{print \"/\" $3}' \n With this command, you have the names of all virtual servers that have this setting and can use that for your change management documentation. There is a slight change in the output of this command, where we have awk add a slash to the object name. When referencing an object in a tmsh command, it can either be just the name of the object if you are in the partition OR you give the full partition name to the command. In some cases where tmsh does not see the partition syntax, it will explicitly insert /Common onto the virtual server name and will fail. \n Now you may notice some virtual server names are much longer and you may see a. app somewhere in the name. That means you have virtual servers that were deployed using iApps. For making batch updates, as we will here, iApps by default, will block attempts to make changes.   \n   \n List iApps with Strict Updates enabled (default value) \n #show deployed iApps that have strict-updates enabled \n#Because this is a default setting, we have to look at all-properties. \ntmsh -c 'cd /; list sys application service recursive one-line all-properties' | grep -E \"strict-updates enabled\" | awk '{ print \"/\" $4 }' \n While we tend to shorthand the objects as iApps, the config calls them an application service and they are stored in the system module versus the ltm module. \n   \n List iApps with Strict Updates disabled  \n If you want to find the iApp names where Strict Updates are disabled, you can change the grep string to find \"strict-updates disabled\" or you can add a -v to the previous grep command. \n #show deployed iApps that have strict-updates disabled method 1 \n#While we do not need the all-properties option, we will keep it for consistency. \ntmsh -c 'cd /; list sys application service recursive one-line all-properties' | grep -E \"strict-updates disabled\" | awk '{ print \"/\" $4 }' \n#show deployed iApps that have strict-updates disabled method 2 \n#While we do not need the all-properties option, we will keep it for consistency. \ntmsh -c 'cd /; list sys application service recursive one-line all-properties' | grep -v \"strict-updates enabled\" | awk '{ print \"/\" $4 }' \n   \n List iApps with Strict Updates enabled for Virtual Servers with default tcp profile in client and server contexts \n Before we make changes to the iApps, we usually want to be very selective in what we select for changes. Due to the location of the two values, the tcp profile in the virtual server, and the strict updates iApp setting, we will use a bash variable to build the search string argument. Because we are only looking for virtual servers built by an iApp, we have to exclude virtual servers that do not have an app-service defined. This is accomplished with the -v option for grep. Next, we have to format the output for a grep friendly OR expression. In this case, we replace the new line character with a pipe character using tr and then we use sed to remove the last pipe character that tr put into the string. \n Note that if the command that feeds inScopeiApp returns nothing, then the final tmsh command will have a grep error when it tries to parse a null (empty) string. \n #List the iApps that are in scope and will interfere with the commands \n#due to app-service none being an implicit default, we must use the all-properties directive to list it in the output. \n#due to strict-updates being enabled by default, we must use the all-properties directive to list it in the output. \ninScopeiApp=$(tmsh -c 'cd /; list ltm virtual recursive one-line all-properties' | grep -E \"Common/tcp { context all }\" | grep -v \"app-service none\" | awk '{print $10 }' | tr '\\n' '|' | sed '$s/.$/\\n/') \ntmsh -c 'cd /; list sys application service recursive one-line all-properties' | grep -E \"strict-updates enabled\" | awk '{ print \"/\" $4 }' | grep -E $inScopeiApp \n   \n List iApps with Strict Updates enabled for Virtual Servers with AAM/WAM based profiles \n Now we are getting a bit more complex and have to go a level deeper to find the defaults-from values of profiles as well as some known profile names. First we build the PROFILES string with the known profile names, and then add in the profile names that have inherited an AAM/WAM profile. Then we get virtual server names that use those profiles to determine the list of iApps that we want to see if we need to disable strict-updates. \n #List the iApps that are in scope and will interfere with the commands \n#due to strict-updates being enabled by default, we must use the all-properties directive to list it in the output. \nPROFILES=\"wam-tcp-lan-optimized|wam-tcp-wan-optimized|wom-tcp-lan-optimized|wom-tcp-wan-optimized|\"$(tmsh -c 'cd /; list ltm profile recursive one-line' | grep -E \"defaults-from.*(wam|wom|webacceleration)\" | awk '{print $4}' | tr '\\n' '|' | sed '$s/.$/\\n/') \ninScopeiApp=$(tmsh -c 'cd /; list ltm virtual recursive one-line all-properties' | grep -E \"(profiles.*($PROFILES))\" | grep -v \"app-service none\" | awk '{print $10 }' | tr '\\n' '|' | sed '$s/.$/\\n/') \ntmsh -c 'cd /; list sys application service recursive one-line all-properties' | grep -E \"strict-updates enabled\" | awk '{ print \"/\" $4 }' | grep -E $inScopeiApp \n   \n Using the lists to make changes \n Everything we have done so far is to find objects of interest to document them for future changes/deletions, etc. Now we will take these lists as input for modifying statements. The tool I chose was xargs because it can write and execute commands based on the inputs you give it. \n   \n Changing the Strict Updates setting in iApps to allow out of band modifications \n It is important to note that while you may loosen this setting to make this change and then set it again, these steps are out of band modifications to the iApp, and as a result, you may never use the Reconfigure GUI nor update the iApp template. Of note, iApps are now deprecated in favor of FAST for AS3. You can read more on that here—https://my.f5.com/manage/s/article/K13422  This example is lifted from K000149084, to find all iApps that use profiles associated with AAM/WAM and disable strict updates. I chose to add the -T option to xargs, so that it would output the commands it was running. This way if there is an error or you need to record what was done, you will have a record of it.  \n #Modify the iApps that are in scope and will interfere with the commands \n#due to strict-updates being enabled by default, we must use the all-properties directive to list it in the output. \n#***IMPORTANT NOTE - This script aims to specifically target ONLY the iApps needed for the steps below to succeed. \n#Once Strict updates are disabled and changes made to the objects, you can no longer update the template or use the Reconfigure screen in the GUI. \nPROFILES=\"wam-tcp-lan-optimized|wam-tcp-wan-optimized|wom-tcp-lan-optimized|wom-tcp-wan-optimized|\"$(tmsh -c 'cd /; list ltm profile recursive one-line' | grep -E \"defaults-from.*(wam|wom|webacceleration)\" | awk '{print $4}' | tr '\\n' '|' | sed '$s/.$/\\n/') \ninScopeiApp=$(tmsh -c 'cd /; list ltm virtual recursive one-line all-properties' | grep -E \"(profiles.*($PROFILES))\" | grep -v \"app-service none\" | awk '{print $10 }' | tr '\\n' '|' | sed '$s/.$/\\n/') \ntmsh -c 'cd /; list sys application service recursive one-line all-properties' | grep -E \"strict-updates enabled\" | awk '{ print \"/\" $4 }' | grep -E $inScopeiApp | xargs -t -I iAppname tmsh modify sys application service iAppname strict-updates disabled \n   \n Changing Parent Profiles for TCP profiles that have AAM/WAM based profiles \n In the last list segment, you were introduced to the code where we scan for known tcp profiles and then a list of profiles that inherited their settings from an AAM/WAM profile. Now we will just look for tcp profiles that inherited their settings from an AAM/WAM profile and change them to use Optimized TCP profiles. Because this is a new iteration, I will show the list of commands separately, for the change management side of things to identify the profiles and the virtual servers that would be impacted. \n #Find TCP profiles with wam/wom based profiles \ntmsh -c 'cd /; list ltm profile tcp recursive one-line' | grep -E \"defaults-from.Common.w(a|o)m-tcp-*\" | awk '{ print \"/\" $4 }' \n#List the virtuals with any profiles that are related to WAM/WOM/AAM \nPROFILES=\"wam-tcp-lan-optimized|wam-tcp-wan-optimized|wom-tcp-lan-optimized|wom-tcp-wan-optimized|\"$(tmsh -c 'cd /; list ltm profile recursive one-line' | grep -E \"defaults-from.*(wam|wom|webacceleration)\" | awk '{print $4}' | tr '\\n' '|' | sed '$s/.$/\\n/') \ntmsh -c 'cd /; list ltm virtual recursive one-line' | grep -E \"(profiles.*($PROFILES))\" | awk '{print \"/\" $3}' \n Due to the requirements of wan side and lan side, the commands are very specific to each context. When updating a virtual server, you have to first add the new profiles and then delete the unwanted ones. When you attempt to delete the profiles first, the system will give you an error as it is a mandatory field. \n *** Note these commands will fail on objects that are a part of an iApp that has strict enabled \n #************************************************************************************************************** \n#These commands will change your configuration, so only use when ready #Find TCP profiles with wam/wom based profiles for lan and replace the defaults-from \ntmsh -c 'cd /; list ltm profile tcp recursive one-line' | grep -E \"defaults-from.Common.w(a|o)m-tcp-lan*\" | awk '{ print \"/\" $4 }' | xargs -t -I tcp_profile tmsh modify ltm profile tcp tcp_profile defaults-from f5-tcp-lan \n\n#Find TCP profiles with wam/wom based profiles for wan and replace the defaults-from \ntmsh -c 'cd /; list ltm profile tcp recursive one-line' | grep -E \"defaults-from.Common.w(a|o)m-tcp-wan*\" | awk '{ print \"/\" $4 }' | xargs -t -I tcp_profile tmsh modify ltm profile tcp tcp_profile defaults-from f5-tcp-wan \n\n#Execute commands for TCP profile updates to the Virtual Servers in all partitons. have to do this in a server side and client side pass to avoid errors \ntmsh -c 'cd /; list ltm virtual recursive one-line' | grep -E \"(profiles.*(w(a|o)m-tcp-lan*))\" | awk '{print \"/\" $3}' | xargs -t -I vsName tmsh modify ltm virtual vsName profiles add { f5-tcp-lan { context serverside } } profiles delete { wam-tcp-lan-optimized } \ntmsh -c 'cd /; list ltm virtual recursive one-line' | grep -E \"(profiles.*(w(a|o)m-tcp-wan*))\" | awk '{print \"/\" $3}' | xargs -t -I vsName tmsh modify ltm virtual vsName profiles add { f5-tcp-wan { context clientside } } profiles delete { wam-tcp-wan-optimized } \n   \n Changing the default TCP profile on Virtual Servers to use Optimized TCP Profiles \n In case you did read Martin Duke's posts about using the base tcp profile Stop Using the Base TCP Profile! or you saw F5 Unveils New Built-In TCP Profiles or you noticed what was used in the new FAST HTTP Template, and want to go all in, well here is the command to change any virtual server that you found in the second example, to use the Optimized TCP Profiles. Unlike our previous tcp profile modification, we can do this in one pass because the Serverside inherited the setting from the Clientside. \n #Execute commands for TCP profile updates to the Virtual Servers in all partitons. \n#We have to add the profiles before we can delete the one we want to remove.do this in a server side and client side pass to avoid errors \ntmsh -c 'cd /; list ltm virtual recursive one-line all-properties' | grep -E \"Common/tcp { context all }\" | awk '{print \"/\" $3}' | xargs -t -I vsName tmsh modify ltm virtual vsName profiles add { f5-tcp-lan { context serverside } } profiles add { f5-tcp-wan { context clientside } } profiles delete { tcp } \n   \n Conclusion \n With these commands, you have gained an understanding of how to look for certain settings and then make the changes you would like.  ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"15585","kudosSumWeight":1,"repliesCount":0,"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:276033":{"__typename":"Conversation","id":"conversation:276033","topic":{"__typename":"TkbTopicMessage","uid":276033},"lastPostingActivityTime":"2024-09-26T14:10:02.028-07:00","solved":false},"User:user:350873":{"__typename":"User","uid":350873,"login":"Karen_Jester_42","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/m_assets/avatars/default/avatar-10.svg?time=0"},"id":"user:350873"},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzYwMzMtMTYwOTlpRTZBOEFGRjNFMjZGRkZDMg?revision=2\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzYwMzMtMTYwOTlpRTZBOEFGRjNFMjZGRkZDMg?revision=2","title":"0151T000003d5HxQAI.jpg","associationType":"BODY","width":454,"height":189,"altText":"null"},"TkbTopicMessage:message:276033":{"__typename":"TkbTopicMessage","subject":"What is an iApp?","conversation":{"__ref":"Conversation:conversation:276033"},"id":"message:276033","revisionNum":2,"uid":276033,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:350873"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":1471},"postTime":"2011-09-21T09:05:07.000-07:00","lastPublishTime":"2024-09-26T14:10:02.028-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" iApp is a seriously cool, game changing technology that was released in F5’s v11. There are so many benefits to our customers with this tool that I am going to break it down over a series of posts. Today we will focus on what it is. \n Hopefully you are already familiar with the power of F5’s iRules technology. If not, here is a quick background. F5 products support a scripting language based on TCL. This language allows an administrator to tell their BIG-IP to intercept, inspect, transform, direct and track inbound or outbound application traffic. An iRule is the bit of code that contains the set of instructions the system uses to process data flowing through it, either in the header or payload of a packet. This technology allows our customers to solve real-time application issues, security vulnerabilities, etc that are unique to their environment or are time sensitive. \n   \n An iApp is like iRules, but for the management plane. Again, there is a scripting language that administrators can build instructions the system will use. But instead of describing how to process traffic, in the case of iApp, it is used to describe the user interface and how the system will act on information gathered from the user. The bit of code that contains these instructions is referred to as an iApp or iApp template. A system administrator can use F5-provided iApp templates installed on their BIG-IP to configure a service for a new application. They will be presented with the text and input fields defined by the iApp author. Once complete, their answers are submitted, and the template implements the configuration. First an application service object (ASO) is created that ties together all the configuration objects which are created, like virtual servers and profiles.  Each object created by the iApp is then marked with the ASO to identify their membership in the application for future management and reporting. \n That about does it for what an iApp is…..next up, how they can work for you. ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"2014","kudosSumWeight":0,"repliesCount":4,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzYwMzMtMTYwOTlpRTZBOEFGRjNFMjZGRkZDMg?revision=2\"}"}}],"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:276126":{"__typename":"Conversation","id":"conversation:276126","topic":{"__typename":"TkbTopicMessage","uid":276126},"lastPostingActivityTime":"2023-11-04T07:11:00.879-07:00","solved":false},"User:user:351379":{"__typename":"User","uid":351379,"login":"Jezmynn_Koh_429","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/m_assets/avatars/default/avatar-4.svg?time=0"},"id":"user:351379"},"TkbTopicMessage:message:276126":{"__typename":"TkbTopicMessage","subject":"F5 Predicts: Education gets personal","conversation":{"__ref":"Conversation:conversation:276126"},"id":"message:276126","revisionNum":1,"uid":276126,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:351379"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":899},"postTime":"2015-09-24T20:38:15.000-07:00","lastPublishTime":"2015-09-24T20:38:15.000-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" The topic of education is taking centre stage today like never before. I think we can all agree that education has come a long way from the days where students and teachers were confined to a classroom with a chalkboard. Technology now underpins virtually every sector and education is no exception. \n\n The Internet is now the principal enabling mechanism by which students assemble, spread ideas and sow economic opportunities. Education data has become a hot topic in a quest to transform the manner in which students learn. According to Steven Ross, a professor at the Centre for Research and Reform in Education at Johns Hopkins University, the use of data to customise education for students will be the key driver for learning in the future[1]. This technological revolution has resulted in a surge of online learning courses accessible to anyone with a smart device.  \n\n A two-year assessment of the massive open online courses (MOOCs) created by HarvardX and MITx revealed that there were 1.7 million course entries in the 68 MOOC [2]. This translates to about 1 million unique participants, who on average engage with 1.7 courses each. \n\n This equity of education is undoubtedly providing vast opportunities for students around the globe and improving their access to education. With more than half a million apps to choose from on different platforms such as the iOS and Android, both teachers and students can obtain digital resources on any subject. \n\n As education progresses in the digital era, here are some considerations for educational institutions to consider: \n\n   \n\n Scale and security \n\n The emergence of a smogasborad of MOOC providers, such as Coursera and edX, have challenged the traditional, geographical and technological boundaries of education today. Digital learning will continue to grow driving the demand for seamless and user friendly learning environments.  \n\n In addition, technological advancements in education offers new opportunities for government and enterprises. It will be most effective if provided these organisations have the ability to rapidly scale and adapt to an all new digital world – having information services easily available, accessible and secured. \n\n Many educational institutions have just as many users as those in large multinational corporations and are faced with the issue of scale when delivering applications. The aim now is no longer about how to get fast connection for students, but how quickly content can be provisioned and served and how seamless the user experience can be. \n\n No longer can traditional methods provide our customers with the horizontal scaling needed. They require an intelligent and flexible framework to deploy and manage applications and resources. \n\n Hence, having an application-centric infrastructure in place to accelerate the roll-out of curriculum to its user base, is critical in addition to securing user access and traffic in the overall environment. \n\n   \n\n Ensuring connectivity \n\n We live in a Gen-Y world that demands a high level of convenience and speed from practically everyone and anything. \n\n This demand for convenience has brought about reform and revolutionised the way education is delivered to students. Furthermore, the Internet of things (IoT), has introduced a whole new raft of ways in which teachers can educate their students. \n\n Whether teaching and learning is via connected devices such as a Smart Board or iPad, seamless access to data and content have never been more pertinent than now. With the increasing reliance on Internet bandwidth, textbooks are no longer the primary means of educating, given that students are becoming more web oriented. The shift helps educational institutes to better personalise the curriculum based on data garnered from students and their work. \n\n   \n\n Duty of care \n\n As the cloud continues to test and transform the realms of education around the world, educational institutions are opting for a centralised services model, where they can easily select the services they want delivered to students to enhance their learning experience. \n\n Hence, educational institutions have a duty of care around the type of content accessed and how it is obtained by students. They can enforce acceptable use policies by only delivering content that is useful to the curriculum, with strong user identification and access policies in place. \n\n By securing the app, malware and viruses can be mitigated from the institute’s environment. From an outbound perspective, educators can be assured that students are only getting the content they are meant to get access to. \n\n   \n\n F5 has the answer \n\n BIG-IP LTM acts as the bedrock for educational organisations to provision, optimise and deliver its services. It provides the ability to publish applications out to the Internet in a quickly and timely manner within a controlled and secured environment. F5 crucially provides both the performance and the horizontal scaling required to meet the highest levels of throughput. \n\n At the same time, BIG-IP APM provides schools with the ability to leverage virtual desktop infrastructure (VDI) applications downstream, scale up and down and not have to install costly VDI gateways on site, whilst centralising the security decisions that come with it. As part of this, custom iApps can be developed to rapidly and consistently deliver, as well as reconfigure the applications that are published out to the Internet in a secure, seamless and manageable way. \n\n BIG-IP Application Security Manager (ASM) provides an application layer security to protect vital educational assets, as well as the applications and content being continuously published. ASM allows educational institutes to tailor security profiles that fit like a glove to wrap seamlessly around every application. It also gives a level of assurance that all applications are delivered in a secure manner. \n\n   \n\n Education tomorrow \n\n It is hard not to feel the profound impact that technology has on education. Technology in the digital era has created a new level of personalised learning. \n\n The time is ripe for the digitisation of education, but the integrity of the process demands the presence of technology being at the forefront, so as to ensure the security, scalability and delivery of content and data. \n\n The equity of education that technology offers, helps with addressing factors such as access to education, language, affordability, distance, and equality. Furthermore, it eliminates geographical boundaries by enabling the mass delivery of quality education with the right policies in place. \n\n   \n\n \n \n   \n\n [1] http://www.wsj.com/articles/SB10001424052702304756104579451241225610478 \n\n [2] http://papers.ssrn.com/sol3/papers.cfm?abstract_id=2586847 \n\n   \n \n ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"6850","kudosSumWeight":0,"repliesCount":3,"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:276612":{"__typename":"Conversation","id":"conversation:276612","topic":{"__typename":"TkbTopicMessage","uid":276612},"lastPostingActivityTime":"2023-07-24T09:26:46.666-07:00","solved":false},"User:user:173160":{"__typename":"User","uid":173160,"login":"ChrisMutzel_151","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/m_assets/avatars/default/avatar-3.svg?time=0"},"id":"user:173160"},"TkbTopicMessage:message:276612":{"__typename":"TkbTopicMessage","subject":"F5 in AWS Part 4 - Orchestrating BIG-IP Application Services with Open-Source tools","conversation":{"__ref":"Conversation:conversation:276612"},"id":"message:276612","revisionNum":2,"uid":276612,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:173160"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":1390},"postTime":"2015-09-29T00:01:00.000-07:00","lastPublishTime":"2023-06-05T22:23:36.514-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Updated for Current Versions and Documentation \n\n Part 1 : AWS Networking Basics Part 2: Running BIG-IP in an EC2 Virtual Private Cloud Part 3: Advanced Topologies and More on Highly-Available Services Part 4: Orchestrating BIG-IP Application Services with Open-Source Tools Part 5: Cloud-init, Single-NIC, and Auto Scale Out of BIG-IP in v12 \n\n The following post references code hosted at F5's Github repository f5networks/aws-deployments. This code provides a demonstration of using open-source tools to configure and orchestrate BIG-IP. \n\n Full documentation for F5 BIG-IP cloud work can be found at Cloud Docs: F5 Public Cloud Integrations. \n\n \n So far we have talked above AWS networking basics, how to run BIG-IP in a VPC, and highly-available deployment footprints. In this post, we’ll move on to my favorite topic, orchestration. \n\n By this point, you probably have several VMs running in AWS. You’ve lost track of which configuration is setup on which VM, and you have found yourself slowly going mad as you toggle between the AWS web portal and several SSH windows.  I call this ‘point-and-click’ purgatory. Let's be blunt, why would you move to cloud without realizing the benefits of automation, of which cloud is a large enabler. \n\n If you remember our second article, we mentioned CloudFormation templates as a great way to deploy a standardized set of resources (perhaps BIG-IP + the additional virtualized network resources) in EC2. This is a great start, but we need to configure these resources once they have started, and we need a way to define and execute workflows which will run across a set of hosts, perhaps even hosts which are external to the AWS environment. Enter the use of open-source configuration management and workflow tools that have been popularized by the software development community. \n\n Open-source configuration management and AWS APIs \n\n Lately, I have been playing with Ansible, which is a python-based, agentless workflow engine for IT automation. By agentless, I mean that you don’t need to install an agent on hosts under management. Ansible, like the other tools, provides a number of libraries (or “modules”) which provide the ability to manage a diverse collection of remote systems. These modules are typically implemented through the use of API calls, often over HTTP. Out of the box, Ansible comes with several modules for managing resources in AWS. While the EC2 libraries provided are useful for basic orchestration use cases, we decided it would be easier to atomically manage sets of resources using the CloudFormation module. In doing so, we were able to deploy entire CloudFormation stacks which would include items like VPCs, networking elements, BIG-IP, app servers, etc. Underneath the covers, the CloudFormation: Ansible module and our own project use the python module to interact with AWS service endpoints. Ansible provides some basic modules for managing BIG-IP configuration resources. These along with libraries for similar tools can be found here: \n\n Ansible Puppet SaltStack \n\n In the rest of this post, I’ll discuss some work colleagues and I have done to automate BIG-IP deployments in AWS using Ansible. While we chose to use Ansible, we readily admit that Puppet, Chef, Salt and whatever else you use  are all appropriate choices for implementing deployment and configuration management workflows for your network. Each have their upsides and downsides, and different tools may lend themselves to different use cases for your infrastructure. Browse the web to figure out which tool is right for you. \n\n Using Standardized BIG-IP Interfaces \n\n Speaking of APIs, for years F5 has provided the ability to programmatically configure BIG-IP using iControlSOAP.  As the audiences performing automation work have matured, so have the weapons of choice.  The new hot ticket is REST (Representational State Transfer), and guess what, BIG-IP has a REST interface (you can probably figure out what it is called).  Together, iControlSOAP and iControlREST give you the power to manage nearly every configuration element and feature of BIG-IP.  These interfaces become extremely powerful when you combine them with your favorite open-source configuration management tool and a cloud that allows you to spin up and down compute and networking resources. \n\n In the project described below, we have also made use of iApps using iControlRest as a way to create a standard virtual server configuration with the correct policies and profiles. The documentation in Github describes this in detail, but our approach shows how iApps provide a strongly supported approach for managing network policy across engineering teams. For example, imagine that a team of software engineers has written a framework to deploy applications. You can package the network policy into iApps for various types of apps, and pass these to the teams writing the deployment framework. \n\n Implementing a Service Catalog \n\n To pull the above concepts together, a colleague and I put together the aws-deployments project. The goal was to build a simple service catalog which would enable a user to deploy a containerized application in EC2 with BIG-IP network services sitting in front. This is example code that is not supported by F5 support but is a proof of concept to show how you can fully automate production-like deployments in AWS. \n\n Some highlights of the project include: \n\n Use of iControlRest and iControlSoap within Ansible playbooks to setup advanced topologies of BIG-IP in AWS. Automated deployment of a basic ASM web application firewall policy to protect a vulnerable web app (Hackazon. Use of iApps to manage virtual server configurations, including the WAF policy mentioned above. \n\n \n\n Figure 1 - Generic Architecture for automating application deployments in public or private cloud \n\n In examination of the code, you will see that we provide the opportunity to provision all the development models outlined in our earlier post (a single standalone VE, standalones BIG-IP VEs striped availability zones, clusters within an availability zone, etc). We used Ansible and the interfaces on BIG-IP to orchestrate the workflows assoiated with these deployment models. To perform the clustering step, we have used the iControlSoap interface on BIG-IP. The final set of technology used is depicted in Figure 3. \n\n \n\n Figure 2 - Technologies used in the aws-deployments project on Github \n\n Read the Code and Test It Yourself \n\n All the code I have mentioned is available at f5networks/aws-deployments. We encourage you to download and run the code for yourself. Instructions for setting up a development environment which includes the necessary dependencies is easy.  We have packaged all the dependencies for use with either Vagrant or Docker as development tools. The instructions for either of these approaches can be found in the README.md or in the /docs directory. The following video shows an end-to-end usage example. (Keep in mind that the code has been updated since this video was produced). \n\n At the end of the day, our goal for this work was to collect customer feedback. Please provide some by leaving a comment below, or by filing ‘pull requests’ or ‘issues’ in Github. In the next few weeks, we will be updating the project to include the Hackazon app mentioned above, show how to cluster BIG-IP across availability zones, and how to deploy an ASM profile with an iApp. \n\n Have fun! ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"7510","kudosSumWeight":1,"repliesCount":3,"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:278591":{"__typename":"Conversation","id":"conversation:278591","topic":{"__typename":"TkbTopicMessage","uid":278591},"lastPostingActivityTime":"2023-06-06T12:24:53.301-07:00","solved":false},"User:user:71536":{"__typename":"User","uid":71536,"login":"Alex__Applebaum","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/m_assets/avatars/default/avatar-6.svg?time=0"},"id":"user:71536"},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzg1OTEtNjk1aTRBQkIzMzBBN0E2MkU4Q0M?revision=3\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzg1OTEtNjk1aTRBQkIzMzBBN0E2MkU4Q0M?revision=3","title":"0151T000003d6syQAA.jpg","associationType":"BODY","width":864,"height":338,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzg1OTEtODExMGk0MEMyQjZCQzAxQkMzQjg0?revision=3\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzg1OTEtODExMGk0MEMyQjZCQzAxQkMzQjg0?revision=3","title":"0151T000003d6szQAA.jpg","associationType":"BODY","width":864,"height":450,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzg1OTEtODEwNmlDQUFBQjlBNUQ5MUNGRjhG?revision=3\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzg1OTEtODEwNmlDQUFBQjlBNUQ5MUNGRjhG?revision=3","title":"0151T000003d6t0QAA.png","associationType":"BODY","width":975,"height":550,"altText":null},"TkbTopicMessage:message:278591":{"__typename":"TkbTopicMessage","subject":"F5 in AWS Part 5 - Cloud-init, Single-NIC, and Auto Scale Out in BIG-IP","conversation":{"__ref":"Conversation:conversation:278591"},"id":"message:278591","revisionNum":3,"uid":278591,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:71536"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":2968},"postTime":"2016-08-17T16:48:00.000-07:00","lastPublishTime":"2023-06-06T12:24:53.301-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Updated for Current Versions and Documentation \n\n Part 1 : AWS Networking Basics Part 2: Running BIG-IP in an EC2 Virtual Private Cloud Part 3: Advanced Topologies and More on Highly-Available Services Part 4: Orchestrating BIG-IP Application Services with Open-Source Tools Part 5: Cloud-init, Single-NIC, and Auto Scale Out of BIG-IP in v12 \n\n The following article covers features and examples in the 12.1 AWS Marketplace release, discussed in the following documentation: \n\n Amazon Web Services: Single NIC BIG-IP VE Amazon Web Services: Auto Scaling BIG-IP VE \n\n You can find the BIG-IP Hourly and BYOL releases in the Amazon marketplace here. \n\n \n BIG-IP utility billing images are available, which makes it a great time to talk about some of the functionality.  So far in Chris’s series, we have discussed some of the highly-available deployment footprints of BIG-IP in AWS and how these might be orchestrated. Several of these footprints leverage BIG-IP's Device Service Clustering (DSC) technology for configuration management across devices and also lend themselves to multi-app or multi-tenant configurations in a shared-service model. But what if you want to deploy BIG-IP on a per-app or per-tenant basis, in a horizontally scalable footprint that plays well with the concepts of elasticity and immutability in cloud? Today we have just the option for you. Before highlighting these scalable deployment models in AWS, we need to cover cloud-init and single-NIC configurations; two important additions to BIG-IP that enable an Auto Scaling topology.  \n\n Elasticity \n\n Elastiity is obviously one of the biggest promises/benefits of cloud. By leveraging cloud, we are essentially tapping into the \"unlimited\" (at least relative to our own datacenters) resources large cloud providers have built. In actual practice, this means adopting new methodologies and approaches to truely deliver this. \n\n Immutablity \n\n In traditional operational model of datacenters, everything was \"actively\" managed. Physical Infrastructure still tends to lend itself to active management but even virtualized services and applications running on top of the infrastructure were actively managed.  For example, servers were patched, code was live upgraded inplace, etc. However, to achieve true elasticity, where things are spinning up or down and more ephemeral in nature, it required a new approach. Instead of trying to patch or upgrade individual instances, the approach was treating them as disposable which meant focusing more on the build process itself. \n\n ex. Netflix's famous Building with Legos approach. \n\n Yes, the concept of golden images/snapshots existed since virtualization but cloud, with self-service, automation and auto scale functionality, forced this to a new level.  Operations focus shifted more towards a consistent and repeatable \"build\" or \"packaging\" effort, with final goal of creating instances that didn't need to be touched, logged into, etc.  \n\n In the specific context of AWS's Auto Scale groups, that means modifying the Auto Scale Group's \"launch config\". The steps for creating the new instances involve either referencing an entirely new image ID or maybe modification to a cloud-init config.  \n\n Cloud-init \n\n What is it? \n\n First, let’s talk about cloud-init as it is used with most Linux distributions.  Most of you who are evaluating or operating in the cloud have heard of it. For those who haven’t, cloud-init is an industry standard for bootstrapping machines at startup.  It provides a simple domain specific language for common infrastructure provisioning tasks. You can read the official docs here.  For the average linux or systems engineer, cloud-init is used to perform tasks such as installing a custom package, updating yum repositories or installing certificates to perform final customizations to a \"base\" or “golden” image.  For example, the Security team might create an approved hardened base image and various Dev teams would use cloud-init to customize the image so it booted up with an ‘identity’ if you will – an application server with an Apache webserver running or a database server with MySQL provisioned. \n\n Let’s start with the most basic \"Hello World\" use of cloud-init, passing in User Data (in this case a simple bash script). If launching an instance via the AWS Console, on the Configure Instance page, navigate down the “Advanced Details”: \n\n \n\n Figure 1: User Data input field  - bash \n\n However, User Data is limited to < 16KBs and one of the real powers of cloud-init came from extending functionality past this boundry and providing a standardized way to provision, or ah humm, \"initialize\" instances. Instead of using unwieldy bash scripts that probed whether it was an Ubuntu or a Redhat instance and used this OS method or that OS method (ex. use apt-get vs. rpm) to install a package, configure users, dns settings, mount a drive, etc. you could pass a yaml file starting with #cloud-config file that did a lot of this heavy lifting for you. \n\n Figure 2: User Data input field - cloud-config \n\n \n\n Similar to one of the benefits of Chef, Puppet, Salt or Ansible, it provided a reliable OS or distribution abstraction but where those approaches require external orchestration to configure instances, this was internally orchestrated from the very first boot which was more condusive to the \"immutable\" workflow.  NOTE: cloud-init also compliments and helps boot strap those tools for more advanced or sophisticated workflows (ex. installing Chef/Puppet to keep long running non-immutable services under operation/management and preventing configuration drift). \n\n This brings us to another important distinction. Cloud-init originated as a project from Canonical (Ubuntu) and was designed for general purpose OSs. The BIG-IP's OS (TMOS) however is a highly customized, hardened OS so most of the modules don't strictly apply. Much of the Big-IP's configuration is consumed via its APIs (TMSH, iControl REST, etc.) and stored in it's database MCPD.  We can still achieve some of the benefits of having cloud-init but instead, we will mostly leverage the simple bash processor. \n\n So when Auto Scaling BIG-IPs, there are a couple of approaches. \n\n 1) Creating a custom image as described in the official documentation. \n\n 2) Providing a cloud-init configuration \n\n This is a little lighter weight approach in that it doesn't require the customization work above.   \n\n 3) Using a combination of the two, creating a custom image and leveraging cloud-init. \n\n For example, you may create a custom image with ASM provisioned, SSL certs/keys installed, and use cloud-init to configure additional environment specific elements. \n\n Disclaimer: Packaging is an art, just look at the rise of Docker and new operating systems. Ideally, the more you bake into the image upfront, the more predictable it will be and faster it deploys. However, the less you build-in, the more flexible you can be. Things like installing libraries, compiling, etc. are usually worth building in the image upfront. However, the BIG-IP is already a hardened image and things like installing libraries is not something required or recommended so the task is more about addressing the last/lighter weight configuration steps. However, depending on your priorities and objectives, installing sensitive keying material, setting credentials, pre-provisioning modules, etc. might make good candidates for investing in building custom images. \n\n Using Cloud-init with CloudFormation templates \n\n Remember when we talked about how you could use CloudFormation templates in a previous post to setup BIG-IP in a standard way? Because the CloudFormation service by itself only gave us the ability to lay down the EC2/VPC infrastructure, we were still left with remaining 80% of the work to do; we needed an external agent or service (in our case Ansible) to configure the BIG-IP and application services. Now, with cloud-init on the BIG-IP (using version 12.0 or later), we can perform that last 80% for you. \n\n Using Cloud-init with BIG-IP \n\n As you can imagine, there’s quite a lot you can do with just that one simple bash script shown above. However, more interestingly, we also installed AWS’s Cloudformation Helper scripts. \n\n http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-helper-scripts-reference.html \n\n to help extend cloud-init and unlock a larger more powerful set of AWS functionality. \n\n So when used with Cloudformation, our User Data simply changes to executing the following AWS Cloudformation helper script instead.  \n\n \n\"UserData\": {\n \"Fn::Base64\": {\n \"Fn::Join\": [\n \"\",\n [\n \"#!/bin/bash\\n\",\n \"/opt/aws/apitools/cfn-init-1.4-0.amzn1/bin/cfn-init -v -s \",\n {\n \"Ref\": \"AWS::StackId\"\n },\n \" -r \",\n \"Bigip1Instance\",\n \" --region \",\n {\n \"Ref\": \"AWS::Region\"\n },\n \"\\n\"\n ]\n ]\n }\n}\n \n\n This allows us to do things like obtaining variables passed in from Cloudformation environment, grabbing various information from the metadata service, creating or downloading files, running particular sequence of commands, etc. so once BIG-IP has finishing running, our entire application delivery service is up and running. \n\n For more information, this page discusses how meta-data is attached to an instance using CloudFormation templates: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-init.html#aws-resource-init-commands. \n\n Example BYOL and Utility CloudFormation Templates \n\n We’ve posted several examples on github to get you started.   \n\n https://github.com/f5networks/f5-aws-cloudformation \n\n In just a few short clicks, you can have an entire BIG-IP deployment up and running. The two examples below will launch an entire reference stack complete with VPCs, Subnets, Routing Tables, sample webserver, etc. and show the use of cloud-init to bootstrap a BIG-IP.  \n\n Cloud-init is used to configure interfaces, Self-IPs, database variables, a simple virtual server, and in the case of of the BYOL instance, to license BIG-IP.  Let’s take a closer look at the BIG-IP resource created in one of these to see what’s going on here: \n\n \n \"Bigip1Instance \": {\n \"Metadata \": {\n \"AWS::CloudFormation::Init \": {\n \"config \": {\n \"files \": {\n \"/tmp/firstrun.config \": {\n \"content \": {\n \"Fn::Join \": [\n \" \",\n [\n \"#!/bin/bash\\n \",\n \"HOSTNAME=`curl http://169.254.169.254/latest/meta-data/hostname`\\n \",\n \"TZ='UTC'\\n \",\n \"BIGIP_ADMIN_USERNAME=' \",\n {\n \"Ref \": \"BigipAdminUsername \"\n },\n \"'\\n \",\n \"BIGIP_ADMIN_PASSWORD=' \",\n {\n \"Ref \": \"BigipAdminPassword \"\n },\n \"'\\n \",\n \"MANAGEMENT_GUI_PORT=' \",\n {\n \"Ref \": \"BigipManagementGuiPort \"\n },\n \"'\\n \",\n \"GATEWAY_MAC=`ifconfig eth0 | egrep HWaddr | awk '{print tolower($5)}'`\\n \",\n \"GATEWAY_CIDR_BLOCK=`curl http://169.254.169.254/latest/meta-data/network/interfaces/macs/${GATEWAY_MAC}/subnet-ipv4-cidr-block`\\n \",\n \"GATEWAY_NET=${GATEWAY_CIDR_BLOCK%/*}\\n \",\n \"GATEWAY_PREFIX=${GATEWAY_CIDR_BLOCK#*/}\\n \",\n \"GATEWAY=`echo ${GATEWAY_NET} | awk -F. '{ print $1\\ \".\\ \"$2\\ \".\\ \"$3\\ \".\\ \"$4+1 }'`\\n \",\n \"VPC_CIDR_BLOCK=`curl http://169.254.169.254/latest/meta-data/network/interfaces/macs/${GATEWAY_MAC}/vpc-ipv4-cidr-block`\\n \",\n \"VPC_NET=${VPC_CIDR_BLOCK%/*}\\n \",\n \"VPC_PREFIX=${VPC_CIDR_BLOCK#*/}\\n \",\n \"NAME_SERVER=`echo ${VPC_NET} | awk -F. '{ print $1\\ \".\\ \"$2\\ \".\\ \"$3\\ \".\\ \"$4+2 }'`\\n \",\n \"POOLMEM=' \",\n {\n \"Fn::GetAtt \": [\n \"Webserver \",\n \"PrivateIp \"\n ]\n },\n \"'\\n \",\n \"POOLMEMPORT=80\\n \",\n \"APPNAME='demo-app-1'\\n \",\n \"VIRTUALSERVERPORT=80\\n \",\n \"CRT='default.crt'\\n \",\n \"KEY='default.key'\\n \"\n ]\n ]\n },\n \"group \": \"root \",\n \"mode \": \"000755 \",\n \"owner \": \"root \"\n },\n \"/tmp/firstrun.utils \": {\n \"group \": \"root \",\n \"mode \": \"000755 \",\n \"owner \": \"root \",\n \"source \": \"http://cdn.f5.com/product/templates/utils/firstrun.utils \"\n }\n \"/tmp/firstrun.sh \": {\n \"content \": {\n \"Fn::Join \": [\n \" \",\n [\n \"#!/bin/bash\\n \",\n \". /tmp/firstrun.config\\n \",\n \". /tmp/firstrun.utils\\n \",\n \"FILE=/tmp/firstrun.log\\n \",\n \"if [ ! -e $FILE ]\\n \",\n \" then\\n \",\n \" touch $FILE\\n \",\n \" nohup $0 0<&- &>/dev/null &\\n \",\n \" exit\\n \",\n \"fi\\n \",\n \"exec 1<&-\\n \",\n \"exec 2<&-\\n \",\n \"exec 1<>$FILE\\n \",\n \"exec 2>&1\\n \",\n \"date\\n \",\n \"checkF5Ready\\n \",\n \"echo 'starting tmsh config'\\n \",\n \"tmsh modify sys ntp timezone ${TZ}\\n \",\n \"tmsh modify sys ntp servers add { 0.pool.ntp.org 1.pool.ntp.org }\\n \",\n \"tmsh modify sys dns name-servers add { ${NAME_SERVER} }\\n \",\n \"tmsh modify sys global-settings gui-setup disabled\\n \",\n \"tmsh modify sys global-settings hostname ${HOSTNAME}\\n \",\n \"tmsh modify auth user admin password \\ \"'${BIGIP_ADMIN_PASSWORD}'\\ \"\\n \",\n \"tmsh save /sys config\\n \",\n \"tmsh modify sys httpd ssl-port ${MANAGEMENT_GUI_PORT}\\n \",\n \"tmsh modify net self-allow defaults add { tcp:${MANAGEMENT_GUI_PORT} }\\n \",\n \"if [[ \\ \"${MANAGEMENT_GUI_PORT}\\ \" != \\ \"443\\ \" ]]; then tmsh modify net self-allow defaults delete { tcp:443 }; fi \\n \",\n \"tmsh mv cm device bigip1 ${HOSTNAME}\\n \",\n \"tmsh save /sys config\\n \",\n \"checkStatusnoret\\n \",\n \"sleep 20 \\n \",\n \"tmsh save /sys config\\n \",\n \"tmsh create ltm pool ${APPNAME}-pool members add { ${POOLMEM}:${POOLMEMPORT} } monitor http\\n \",\n \"tmsh create ltm policy uri-routing-policy controls add { forwarding } requires add { http } strategy first-match legacy\\n \",\n \"tmsh modify ltm policy uri-routing-policy rules add { service1.example.com { conditions add { 0 { http-uri host values { service1.example.com } } } actions add { 0 { forward select pool ${APPNAME}-pool } } ordinal 1 } }\\n \",\n \"tmsh modify ltm policy uri-routing-policy rules add { service2.example.com { conditions add { 0 { http-uri host values { service2.example.com } } } actions add { 0 { forward select pool ${APPNAME}-pool } } ordinal 2 } }\\n \",\n \"tmsh modify ltm policy uri-routing-policy rules add { apiv2 { conditions add { 0 { http-uri path starts-with values { /apiv2 } } } actions add { 0 { forward select pool ${APPNAME}-pool } } ordinal 3 } }\\n \",\n \"tmsh create ltm virtual /Common/${APPNAME}-${VIRTUALSERVERPORT} { destination 0.0.0.0:${VIRTUALSERVERPORT} mask any ip-protocol tcp pool /Common/${APPNAME}-pool policies replace-all-with { uri-routing-policy { } } profiles replace-all-with { tcp { } http { } } source 0.0.0.0/0 source-address-translation { type automap } translate-address enabled translate-port enabled }\\n \",\n \"tmsh save /sys config\\n \",\n \"date\\n \",\n \"# typically want to remove firstrun.config after first boot\\n \",\n \"# rm /tmp/firstrun.config\\n \"\n ]\n ]\n },\n \"group \": \"root \",\n \"mode \": \"000755 \",\n \"owner \": \"root \"\n }\n },\n \"commands \": {\n \"b-configure-Bigip \": {\n \"command \": \"/tmp/firstrun.sh\\n \"\n }\n }\n }\n }\n },\n \"Properties \": {\n \"ImageId \": {\n \"Fn::FindInMap \": [\n \"BigipRegionMap \",\n {\n \"Ref \": \"AWS::Region \"\n },\n {\n \"Ref \": \"BigipPerformanceType \"\n }\n ]\n },\n \"InstanceType \": {\n \"Ref \": \"BigipInstanceType \"\n },\n \"KeyName \": {\n \"Ref \": \"KeyName \"\n },\n \"NetworkInterfaces \": [\n {\n \"Description \": \"Public or External Interface \",\n \"DeviceIndex \": \"0 \",\n \"NetworkInterfaceId \": {\n \"Ref \": \"Bigip1ExternalInterface \"\n }\n }\n ],\n \"Tags \": [\n {\n \"Key \": \"Application \",\n \"Value \": {\n \"Ref \": \"AWS::StackName \"\n }\n },\n {\n \"Key \": \"Name \",\n \"Value \": {\n \"Fn::Join \": [\n \" \",\n [\n \"BIG-IP: \",\n {\n \"Ref \": \"AWS::StackName \"\n }\n ]\n ]\n }\n }\n ],\n \"UserData \": {\n \"Fn::Base64 \": {\n \"Fn::Join \": [\n \" \",\n [\n \"#!/bin/bash\\n \",\n \"/opt/aws/apitools/cfn-init-1.4-0.amzn1/bin/cfn-init -v -s \",\n {\n \"Ref \": \"AWS::StackId \"\n },\n \" -r \",\n \"Bigip1Instance \",\n \" --region \",\n {\n \"Ref \": \"AWS::Region \"\n },\n \"\\n \"\n ]\n ]\n }\n }\n },\n \"Type \": \"AWS::EC2::Instance \"\n }\n \n\n Above may look like a lot at first but high level, we start by creating some files \"inline\" as well as “sourcing” some files from a remote location. \n\n /tmp/firstrun.config  - Here we create a file inline, laying down variables from the Cloudformation Stack deployment itself and even the metadata service (http://169.254.169.254/latest/meta-data/). Take a look at the “Ref” stanzas. When this file is laid down on the BIG-IP disk itself, those variables will be interpolated and contain the actual contents. The idea here is to try to keep config and execution separate.  \n\n /tmp/firstrun.utils – These are just some helper functions to help with initial provisioning. We use those to determine when the BIG-IP is ready for this particular configuration (ex. after a licensing or provisioning step). Note that instead of creating the file inline like the config file above, we simply “source” or download the file from a remote location.    /tmp/firstrun.sh – This file is created inline as well and where it really all comes together. The first thing we do is load config variables from the firstrun.conf file and load the helper functions from firstrun.utils. We then create separate log file (/tmp/firstrun.log) to capture the output of this particular script. Capturing the output of these various commands just helps with debugging runs. Then we run a function called checkF5Ready (that we loaded from that helper function file) to make sure BIG-IP’s database is up and ready to accept a configuration. The rest may look more familiar and where most of the user customization takes place. We use variables from the config file to configure the BIG-IP using familiar methods like TMSH and iControl REST.  Technically, you could lay down an entire config file (like SCF) and load it instead.  We use tmsh here for simplicity. The possibilities are endless though.      \n\n Disclaimer: the specific implementation above will certainly be optimized and evolve but the most important take away is we can now leverage cloud-init and AWS's helper libraries to help bootstrap the BIG-IP into a working configuration from the very first boot! \n\n Debugging Cloud-init \n\n What if something goes wrong?  Where do you look for more information?  \n\n The first place you might look is in various cloud-init logs in /var/log (cloud-init.log, cfn-init.log, cfn-wire.log): \n\n Below is an example for the CFTs below: \n\n \n[admin@ip-10-0-0-205:NO LICENSE:Standalone] log # tail -150 cfn-init.log\n2016-01-11 10:47:59,353 [DEBUG] CloudFormation client initialized with endpoint https://cloudformation.us-east-1.amazonaws.com\n2016-01-11 10:47:59,353 [DEBUG] Describing resource BigipEc2Instance in stack arn:aws:cloudformation:us-east-1:452013943082:stack/as-testing-byol-bigip/07c962d0-b893-11e5-9174-500c217b4a62\n2016-01-11 10:47:59,782 [DEBUG] Not setting a reboot trigger as scheduling support is not available\n2016-01-11 10:47:59,790 [INFO] Running configSets: default\n2016-01-11 10:47:59,791 [INFO] Running configSet default\n2016-01-11 10:47:59,791 [INFO] Running config config\n2016-01-11 10:47:59,792 [DEBUG] No packages specified\n2016-01-11 10:47:59,792 [DEBUG] No groups specified\n2016-01-11 10:47:59,792 [DEBUG] No users specified\n2016-01-11 10:47:59,792 [DEBUG] Writing content to /tmp/firstrun.config\n2016-01-11 10:47:59,792 [DEBUG] No mode specified for /tmp/firstrun.config\n2016-01-11 10:47:59,793 [DEBUG] Writing content to /tmp/firstrun.sh\n2016-01-11 10:47:59,793 [DEBUG] Setting mode for /tmp/firstrun.sh to 000755\n2016-01-11 10:47:59,793 [DEBUG] Setting owner 0 and group 0 for /tmp/firstrun.sh\n2016-01-11 10:47:59,793 [DEBUG] Running command b-configure-BigIP\n2016-01-11 10:47:59,793 [DEBUG] No test for command b-configure-BigIP\n2016-01-11 10:47:59,840 [INFO] Command b-configure-BigIP succeeded\n2016-01-11 10:47:59,841 [DEBUG] Command b-configure-BigIP output: % Total % Received % Xferd Average Speed\nTime Time Time Current\n Dload Upload Total Spent Left Speed\n0 40 0 40 0 0 74211 0 --:--:-- --:--:-- --:--:-- 40000\n \n\n \n2016-01-11 10:47:59,841 [DEBUG] No services specified\n2016-01-11 10:47:59,844 [INFO] ConfigSets completed\n2016-01-11 10:47:59,851 [DEBUG] Not clearing reboot trigger as scheduling support is not available\n[admin@ip-10-0-0-205:NO LICENSE:Standalone] log #\n \n\n If trying out the example templates above, you can inspect the various files mentioned.  \n\n Ex. In addition to checking for their general presence: /tmp/firstrun.config = make sure variables were passed as you expected.  /tmp/firstrun.utils = Make sure exists and was downloaded /tmp/firstrun.log = See if any obvious errors were outputted. \n\n It may also be worth checking AWS Cloudformation Console to make sure you passed the parameters you were expecting. \n\n Single-NIC \n\n Another one of the important building blocks introduced with 12.0 on AWS and Azure Virtual Editions is the ability to run BIG-IP with just a single network interface. Typically, BIG-IPs were deployed in a multi-interface model, where interfaces were attached to an out-of-band management network and one or more traffic (or \"data-plane\") networks. But, as we know, cloud architectures scale by requiring simplicity, especially at the network level. To this day, some clouds can only support instances with a single IP on a single NIC. In AWS’s case, although they do support multiple NIC/multiple IP, some of their services like ELB only point to first IP address of the first NIC. So this Single-NIC configuration makes it not only possible but also dramatically easier to deploy in these various architectures. \n\n How this works: \n\n We can now attach just one interface to the instance and BIG-IP will start up, recognize this, use DHCP to configure the necessary settings on that interface.   \n\n Underneath the hood, the following DB keys will be set: \n\n \nadmin@(ip-10-0-1-65)(cfg-sync Standalone)(Active)(/Common)(tmos)# list sys db provision.1nic one-line\nsys db provision.1nic { value \"enable\" }\n \n\n \nadmin@(ip-10-0-1-65)(cfg-sync Standalone)(Active)(/Common)(tmos)# list sys db provision.1nicautoconfig one-line\nsys db provision.1nicautoconfig { value \"enable\" }\n \n\n\n\n provision.1nic = allows both management and data-plane to use the same interface provision.1nicautoconfig = uses address from DHCP to configure a vlan, Self-IP and default gateway.  \n\n Ex. network objects automatically configured \n\n \nadmin@(ip-10-0-1-65)(cfg-sync Standalone)(Active)(/Common)(tmos)# list net vlan\nnet vlan internal\n if-index 112\n interfaces {\n 1.0 { }\n }\n tag 4094\n}\n \n\n \nadmin@(ip-10-0-1-65)(cfg-sync Standalone)(Active)(/Common)(tmos)# list net self\nnet self self_1nic {\n address 10.0.1.65/24\n allow-service {\n default\n }\n traffic-group traffic-group-local-only\n vlan internal\n}\n \n\n \nadmin@(ip-10-0-1-65)(cfg-sync Standalone)(Active)(/Common)(tmos)# list net route\nnet route default {\n gw 10.0.1.1\n network default\n}\n \n\n Note: Traffic Management Shell and the Configuration Utility (GUI) are still available on ports 22 and 443 respectively.  If you want to run the management GUI on a higher port (for instance if you don’t have the BIG-IPs behind a Port Address Translation service (like ELB) and want to run an HTTPS virtual on 443), use the following commands: \n\n \ntmsh modify sys httpd ssl-port 8443\ntmsh modify net self-allow defaults add { tcp:8443 }\ntmsh modify net self-allow defaults delete { tcp:443 }\n \n\n WARNING:  Now that management and dataplane run on the same interface, make sure to modify your Security Groups to restrict access to SSH and whatever port you use for the Mgmt GUI port to trusted networks. \n\n UPDATE: On Single-Nic, Device Service Clustering currently only supports Configuration Syncing (Network Failover is restricted for now due to BZ-606032).  \n\n In general, the single-NIC model lends itself better to single-tenant or per-app deployments, where you need the advanced services from BIG-IP like content routing policies, iRules scripting, WAF, etc. but don’t necessarily care for maintaining a management subnet in the deployment and are just optimizing or securing a single application. By single tenant we also mean single management domain as you're typically running everything through a single wildcard virtual (ex. 0.0.0.0/0, 0.0.0.0/80, 0.0.0.0/443, etc.) vs. giving each tenant its own Virtual Server (usually with its own IP and configuration) to manage. \n\n However, you can still technically run multiple applications behind this virtual with a policy or iRule, where you make traffic steering decisions based on L4-L7 content (SNI, hostname headers, URIs, etc.). In addition, if the BIG-IPs are sitting behind a Port Address Translation service, it also possible to stack virtual services on ports instead. \n\n Ex. 0.0.0.0:444 = Virtual Service 1 0.0.0.0:445 = Virtual Service 2 0.0.0.0:446 = Virtual Service 3 \n\n  We’ll let you get creative here…. \n\n BIG-IP Auto Scale \n\n Finally, the last component of Auto Scaling BIG-IPs involves building scaling policies via Cloudwatch Alarms. In addition to the built-in EC2 metrics in CloudWatch, BIG-IP can report its own set of metrics, shown below: \n\n \n\n Figure 3: Cloudwatch metrics \n\n to scale BIG-IPs based on traffic load. \n\n This can be configured with the following TMSH commands on any version 12.0 or later build: \n\n \ntmsh modify sys autoscale-group autoscale-group-id ${BIGIP_ASG_NAME}\ntmsh load sys config merge file /usr/share/aws/metrics/aws-cloudwatch-icall-metrics-config\n \n\n These commands tell BIG-IP to push the above metrics to a custom “Namespace” on which we can roll up data via standard aggregation functions (min, max, average, sum).  This namespace (based on Auto Scale group name) will appear as a row under in the “Custom metrics” dropdown on the left side-bar in CloudWatch (left side of Figure 1).  Once these BIG-IP or EC2 metrics have been populated, CloudWatch alarms can be built, and these alarms are available for use in Auto Scaling policies for the BIG-IP Auto Scale group. (Amazon provides some nice instructions here).   \n\n Auto Scaling Pool Members and Service Discovery \n\n If you are scaling your ADC tier, you are likely also going to be scaling your application as well.  There are two options for discovering pool members in your application's auto scale group. \n\n 1) FQDN Nodes \n\n For example, in a typical sandwich deployment, your application members might also be sitting behind an internal ELB so you would simply point your FQDN node at the ELB's DNS. For more information, please see: \n\n https://support.f5.com/kb/en-us/products/big-ip_ltm/manuals/product/ltm-implementations-12-1-0/25.html?sr=56133323 \n\n 2) BIG-IP's AWS Auto Scale Pool Member Discovery feature (introduced v12.0) \n\n This feature polls the Auto Scale Group via API calls and populates the pool based on its membership. For more information, please see: \n\n https://support.f5.com/kb/en-us/products/big-ip_ltm/manuals/product/bigip-ve-autoscaling-amazon-ec2-12-1-0/2.html \n\n Putting it all together \n\n The high-level steps for Auto Scaling BIG-IP include the following: \n\n Optionally* creating an ElasticLoadBalancer group which will direct traffic to BIG-IPs in your Auto Scale group once they become operational.  Otherwise, will need Global Server Load Balancing (GSLB). Creating a launch configuration in EC2 (referencing either custom image id and/or using Cloud-init scripts as described above) Creating an Auto Scale group using this launch configuration Creating CloudWatch alarms using the EC2 or custom metrics reported by BIG-IP. Creating scaling policies for your BIG-IP Auto Scale group using the alarms above.  You will want to create both scale up and scale down policies. \n\n Here are some things to keep in mind when Auto Scaling BIG-IP \n\n ● BIG-IP must run in a single-interface configuration with a wildcard listener (as we talked about earlier). This is required because we don't know what IP address the BIG-IP will get. ● Auto Scale Groups themselves consist of utility instances of BIG-IP ● The scale up time for BIG-IP is about 12-20 minutes depending on what is configured or provisioned.  While this may seem like a long-time, creating the right scaling policies (polling intervals, thresholds, unit of scale) make this a non-issue. ● This deployment model lends itself toward the themes of stateless, horizontal scalability and immutability embraced by the cloud. Currently, the config on each device is updated once and only once at device startup. The only way to change the config will be through the creation of a new image or modification to the launch configuration.  Stay tuned for a clustered deployment which is managed in a more traditional operational approach. \n\n If interesting in exploring Auto Scale further, we have put together some examples of scaling the BIG-IP tier here: \n\n https://github.com/f5devcentral/f5-aws-autoscale \n\n * Above github repository also provides some examples of incorporating BYOL instances in the deployment to help leverage BYOL instances for your static load and using Auto Scale instances for your dynamic load. See the READMEs for more information. \n\n CloudFormation templates with Auto Scaled BIG-IP and Application \n\n Need some ideas on how you might leverage these solutions?  Now that you can completely deploy a solution with a single template, how about building service catalog items for your business units that deploy different BIG-IP services (LB, WAF) or a managed service build on top of AWS that can be easily deployed each time you on-board a new customer? ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"31239","kudosSumWeight":0,"repliesCount":7,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzg1OTEtNjk1aTRBQkIzMzBBN0E2MkU4Q0M?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzg1OTEtODExMGk0MEMyQjZCQzAxQkMzQjg0?revision=3\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzg1OTEtODEwNmlDQUFBQjlBNUQ5MUNGRjhG?revision=3\"}"}}],"totalCount":3,"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:285874":{"__typename":"Conversation","id":"conversation:285874","topic":{"__typename":"TkbTopicMessage","uid":285874},"lastPostingActivityTime":"2023-06-05T22:58:59.642-07:00","solved":false},"User:user:354407":{"__typename":"User","uid":354407,"login":"Robert_Haynes","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/m_assets/avatars/default/avatar-10.svg?time=0"},"id":"user:354407"},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODU4NzQtOTgxN2kzMEI1QjBFNDczQUVFNzgx?revision=2\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODU4NzQtOTgxN2kzMEI1QjBFNDczQUVFNzgx?revision=2","title":"0151T000003d6lMQAQ.png","associationType":"BODY","width":516,"height":382,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODU4NzQtNTUyaTg2NjI2RjM1QjE1RDRBQjc?revision=2\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODU4NzQtNTUyaTg2NjI2RjM1QjE1RDRBQjc?revision=2","title":"0151T000003d6iwQAA.png","associationType":"BODY","width":363,"height":200,"altText":null},"TkbTopicMessage:message:285874":{"__typename":"TkbTopicMessage","subject":"Building Application Delivery Services from Templates using the REST API (for People Like Me).","conversation":{"__ref":"Conversation:conversation:285874"},"id":"message:285874","revisionNum":2,"uid":285874,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:354407"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":954},"postTime":"2016-02-02T13:10:43.000-08:00","lastPublishTime":"2023-06-05T22:58:59.642-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" I’ve talked before about the value of Application Policies (AKA Service Templates, AKA iApp Templates). So has my esteemed colleague Nathan Pearce. We think they are pretty important, especially if you’re looking to deploy complex application delivery services using automation tools. \n\n There are quite a lot of resources availabe to help you do this, including a great guide from Chris Mutzel, and some cool Python scripts and tools from the shy and retiring Hitesh Patel on Github.  These are great, and if you are up to speed on iControl and REST then stop reading this and head to one of those places. They are clever over there. \n\n However, to steal a line: “I’m not a smart man” (that’s probably why I’ve ended up as an explainer, rather than a true creator.) I needed some more basic information and examples before I moved on to these. I thought it might be worth documenting my journey, if nothing else for the amusement of others. \n\n First REST – I read up on the BIG-IP REST API here. There is a lot of useful information there. \n\n Now our service template implementation – iApp Templates and their resultant Application Services. For the purposes of this first blog we are going to be using about the most basic template – HTTP.  This template simply creates a standard L7 VIP with a pool of servers at the backend. Jump on a BIG-IP and take a look – it’s pretty simple: \n\n \n\n We are going to stick with straight HTTP, port 80 for now. This is just to understand the template and how to create a service using it via the REST API.  To keep this as simple as possible we’ll be using the Chrome Advanced REST Client.  You can use other tools like curl or the REST client of your choice, of course. \n\n The first thing we are going to do is to create a new application service on the BIG-IP using the GUI. What? Yes, I know that seems backwards – but first we need to see what a deployed service looks like when we qurey it using REST. If anyone blagged their way through Visual Basic for Applications by mainly recording macro steps and then editing the resulting code, you know what I’m talking about. \n\n So here we have the resulting service – note that the pool members are dummies - they don’t exist so the monitor will mark them as down. \n\n \n\n\n\n OK, so what does this look like if you query for it using REST? Lets find out by executing a GET in the REST client with this URL: \n\n \nhttps://<my-bigip>/mgmt/tm/sys/application/service/~Common~test1.app~test1?expandSubcollections=true \n\n So what does all that mean?  Well the first bit is obvious, even to me. “ https://<my-bigip> ” is the address of the BIG-IP, not much to ponder there.  Now we have the path to the API section that gets us to application services “ /mgmt/tm/sys/application/service/ ” – there is a good post explaining how this works here. Full documentation for the URLs/modules are in the REST user guide.  Now we get down to our deployed service “ /~Common~test1.app~test1 ”.  This one is maybe a little harder to get. First you need to know that some of our resource names have a “/” in their name  - to get around that we simply replace “/” with “~” in the URL. If you were to query all the application services on the BIG-IP using \n\n \nhttps://<my-bigip>/mgmt/tm/sys/application/service/ \n\n If you are using the advanced REST client display this using the JSON tab to get a nice color coded output. \n\n You would be able to see the key value pair \"fullPath\": \"/Common/test1.app/test1\" – that’s what we are representing with our “~Common~test1.app~test1 ” . I’m sure there is an excellent architectural reason for why this is the full path, and one day I’ll find the motivation to go and discover it. But today is not that day, today I want to make something work. Finally there is the query string \n\n \n“?expandSubcollections=true” \n\n This simply expands any objects that are part of the application service but also an object in their own right – known as subcollections. A great example is a pool member of a pool. The pool is an object with its own properties (such as load balancing algorithm) that also contains a collection of pool members that each have their own properties (e.g. address, port, connection limit).  In this instance it actually makes no difference in this example, but it may well do so later so we will leave it in. Subcollections are nicely explained here.   \n\n Still with me? Great. Let’s take a look at the output of the GET: \n\n \n {\"kind\":\"tm:sys:application:service:servicestate\",\n\"name\":\"test1\",\"partition\":\"Common\",\n\"subPath\":\"test1.app\",\n\"fullPath\":\"/Common/test1.app/test1\",\n\"generation\":188, \n\"selfLink\":\"https://localhost/mgmt/tm/sys/application/service/~Common~test1.app~test1?expandSubcollections=true&ver=12.0.0\",\n\"deviceGroup\":\"none\",\n\"inheritedDevicegroup\":\"true\",\n\"inheritedTrafficGroup\":\"true\",\"strictUpdates\":\"enabled\",\n\"template\":\"/Common/f5.http\",\n\"templateReference\":{\"link\":\"https://localhost/mgmt/tm/sys/application/template/~Common~f5.http?ver=12.0.0\"},\n\"templateModified\":\"no\",\n\"trafficGroup\":\"/Common/traffic-group-1\",\n\"trafficGroupReference\":{\"link\":\"https://localhost/mgmt/tm/cm/traffic-group/~Common~traffic-group-1?ver=12.0.0\"},\n\"tables\":[{\"name\":\"basic__snatpool_members\"},\n{\"name\":\"net__snatpool_members\"},\n{\"name\":\"optimizations__hosts\"},\n{\"name\":\"pool__hosts\",\"columnNames\":[\"name\"],\n\"rows\":[{\"row\":[\"test.test.com\"]}]},\n{\"name\":\"pool__members\",\n\"columnNames\":[\"addr\",\"port\",\"connection_limit\"],\n\"rows\":[{\"row\":[\"10.0.0.10\",\"80\",\"0\"]}]},\n{\"name\":\"server_pools__servers\"}],\n\"variables\":[{\"name\":\"client__http_compression\",\n\"encrypted\":\"no\",\"value\":\"/#create_new#\"},\n{\"name\":\"monitor__monitor\",\"encrypted\":\"no\",\"value\":\"/#create_new#\"},\n{\"name\":\"monitor__response\",\"encrypted\":\"no\",\"value\":\"none\"},\n{\"name\":\"monitor__uri\",\"encrypted\":\"no\",\"value\":\"/\"},\n{\"name\":\"net__client_mode\",\"encrypted\":\"no\",\"value\":\"wan\"},\n{\"name\":\"net__server_mode\",\"encrypted\":\"no\",\"value\":\"lan\"},\n{\"name\":\"pool__addr\",\"encrypted\":\"no\",\"value\":\"10.0.1.28\"},\n{\"name\":\"pool__pool_to_use\",\"encrypted\":\"no\",\"value\":\"/#create_new#\"},\n{\"name\":\"pool__port\",\"encrypted\":\"no\",\"value\":\"80\"},\n{\"name\":\"ssl__mode\",\"encrypted\":\"no\",\"value\":\"no_ssl\"},\n{\"name\":\"ssl_encryption_questions__advanced\",\"encrypted\":\"no\",\"value\":\"no\"},\n{\"name\":\"ssl_encryption_questions__help\",\"encrypted\":\"no\",\"value\":\"hide\"}\n]\n} \n\n\n\n OK, so now we just need to do a quick match up with the properties we created via the GUI to see what everything means. \n\n\n\n \n{\"kind\":\"tm:sys:application:service:servicestate\",\n\"name\":\"test1\",\"partition\":\"Common\",\n\"subPath\":\"test1.app\",\n\"fullPath\":\"/Common/test1.app/test1\",\n\"generation\":188,\n\"selfLink\":\"https://localhost/mgmt/tm/sys/application/service/~Common~test1.app~test1? \n\n \"Test1\" - That’s  the the name of our application service. Easy. Now let’s ignore some other bits until we get to another section we recognize. \n\n \n{\"name\":\"pool__members\",\n\"columnNames\":[\"addr\",\"port\",\"connection_limit\"],\n\"rows\":[{\"row\":[\"10.0.0.10\",\"80\",\"0\"]} \n\n This is the line that defines the pool members – because there can be more than one we define a list of columns and then the rows afterwards. After that there are lines that instruct the iApp to create new monitors, set the TCP profiles, turn on or off compression etc. Now we get to another important line: \n\n \n{\"name\":\"pool__addr\",\"encrypted\":\"no\",\"value\":\"10.0.1.28\"} \n\n That’s the virtual server address, then the port is next. \n\n \n{\"name\":\"pool__port\",\"encrypted\":\"no\",\"value\":\"80\"} \n\n Why, you are asking, is this the ‘ pool_address ’ and not ‘ VS_address ’? Honestly – I have no idea. I could find out, but that won’t get either of us anywhere and I have a stack of books to read and records to listen to. \n\n So actually, there we have it, just a few key lines that define a simple iApp service. That’s probably enough to create a new one right? So let’s try doing a POST with this body: \n\n\n\n \n{\"kind\":\"tm:sys:application:service:servicestate\",\n\"name\":\"test2\",\"partition\":\"Common\",\n\"subPath\":\"test2.app\",\n\"fullPath\":\"/Common/test2.app/test2\",\n\"generation\":485,\n\"selfLink\":\"https://localhost/mgmt/tm/sys/application/service/~Common~test2.app~test2?ver=12.0.0\",\n\"deviceGroup\":\"none\",\n\"inheritedDevicegroup\":\"true\",\n\"inheritedTrafficGroup\":\"false\",\n\"strictUpdates\":\"enabled\",\n\"template\":\"/Common/f5.http\",\n\"templateReference\":{\"link\":\"https://localhost/mgmt/tm/sys/application/template/~Common~f5.http?ver=12.0.0\"},\n\"templateModified\":\"no\",\"trafficGroup\":\"/Common/traffic-group-1\",\n\"trafficGroupReference\":{\"link\":\"https://localhost/mgmt/tm/cm/traffic-group/~Common~traffic-group-1?ver=12.0.0\"},\n\"tables\":[{\"name\":\"basic__snatpool_members\"},\n{\"name\":\"net__snatpool_members\"},\n{\"name\":\"optimizations__hosts\"},\n{\"name\":\"pool__hosts\",\n\"columnNames\":[\"name\"],\n\"rows\":[{\"row\":[\"test2.test.com\"]}]},\n{\"name\":\"pool__members\",\n\"columnNames\":[\"addr\",\"port\",\"connection_limit\"],\n\"rows\":[{\"row\":[\"10.0.0.20\",\"80\",\"0\"]}]},\n{\"name\":\"server_pools__servers\"}],\n\"variables\":[{\"name\":\"client__http_compression\",\n\"encrypted\":\"no\",\"value\":\"/#create_new#\"},\n{\"name\":\"monitor__monitor\",\n\"encrypted\":\"no\",\"value\":\"/#create_new#\"},\n{\"name\":\"monitor__response\",\"encrypted\":\"no\",\"value\":\"none\"},\n{\"name\":\"monitor__uri\",\"encrypted\":\"no\",\"value\":\"/\"},\n{\"name\":\"net__client_mode\",\"encrypted\":\"no\",\"value\":\"wan\"},\n{\"name\":\"net__server_mode\",\"encrypted\":\"no\",\"value\":\"lan\"},\n{\"name\":\"pool__addr\",\"encrypted\":\"no\",\"value\":\"10.0.0.30\"},\n{\"name\":\"pool__pool_to_use\",\"encrypted\":\"no\",\"value\":\"/#create_new#\"},\n{\"name\":\"pool__port\",\"encrypted\":\"no\",\"value\":\"80\"},\n{\"name\":\"ssl__mode\",\"encrypted\":\"no\",\"value\":\"no_ssl\"},\n{\"name\":\"ssl_encryption_questions__advanced\",\"encrypted\":\"no\",\"value\":\"no\"},\n{\"name\":\"ssl_encryption_questions__help\",\"encrypted\":\"no\",\"value\":\"hide\"}\n]} \n\n POST this, and your return should be similar to the GET we did before, but with your new variables. Check the GUI and see what we have: \n\n \n\n Looks like we’ve just created a new service. Go us. \n\n Let’s expand out the test2 application service: \n\n   \n\n\n\n There you go – we have created a new configuration from a template in a fairly easy manner. Now I know that the Advanced REST API client is not a scalable enterprise automation tool, but it exposes the heart of how this works and now you might be in a better position to automate with the tool of your choice. \n\n Next I’m going to work out how to do an update to the config and redeploy it. Stay tuned. \n\n (Note - I'm sorry about the typo riddled earlier version of this article. There were a combination of technological and meat-bag failures. As I say below - \"I'm not a smart man\". Thanks to those that pointed out my many errors, and no thanks to my blog writing app.) ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"10771","kudosSumWeight":0,"repliesCount":4,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODU4NzQtOTgxN2kzMEI1QjBFNDczQUVFNzgx?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODU4NzQtNTUyaTg2NjI2RjM1QjE1RDRBQjc?revision=2\"}"}}],"totalCount":2,"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:289077":{"__typename":"Conversation","id":"conversation:289077","topic":{"__typename":"TkbTopicMessage","uid":289077},"lastPostingActivityTime":"2023-06-05T22:51:33.558-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"},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwNzctODUwMGk5N0NBQjEzRDg0MDYxMUU1?revision=2\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwNzctODUwMGk5N0NBQjEzRDg0MDYxMUU1?revision=2","title":"0151T000003d6raQAA.png","associationType":"BODY","width":1547,"height":1031,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwNzctMTU2MzNpMkY2RTk4MDYyNDAzQzk3OA?revision=2\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwNzctMTU2MzNpMkY2RTk4MDYyNDAzQzk3OA?revision=2","title":"0151T000003d6rbQAA.png","associationType":"BODY","width":1880,"height":937,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwNzctOTE4MGk3NkFEQjI1QjRBM0MxNkNF?revision=2\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwNzctOTE4MGk3NkFEQjI1QjRBM0MxNkNF?revision=2","title":"0151T000003d6rcQAA.png","associationType":"BODY","width":1637,"height":951,"altText":null},"TkbTopicMessage:message:289077":{"__typename":"TkbTopicMessage","subject":"Getting Started with iApps: Modifying an Existing iApp","conversation":{"__ref":"Conversation:conversation:289077"},"id":"message:289077","revisionNum":2,"uid":289077,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:51154"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":1884},"postTime":"2016-06-22T17:00:00.000-07:00","lastPublishTime":"2023-06-05T22:51:33.558-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Now that the esteemed Chase Abbott has blazed the trail with all the iApps foundational goodness surrounding concepts and components in the first two articles in this Getting Started with iApps series, we can move into the practical! In this article, we'll start small, copying an existing iApp template and modifying it slightly. \n The IP Forwarding iApp \n Before we rip open the hood and dismount the engine, let's first take a walk through to evaluate the existing options. \n \n \n \n As indicated in the video above, we're going to make a couple modifications to this iApp. \n I don't want the end user of the iApp to have ability to forward all traffic as a default option, regardless of IP version. I want to make sure the port is all ports; no port specification supported. I want to disable the advanced features altogether, removing the ability to specify the fastL4 profile and iRules. \n Now that we've established what we're going to do, let's get it done! \n Existing Template \n The existing template is shown by section below:  \n Implementation Presentation \n \n \npackage require iapp 1.0.0\niapp::template start\n\nset app $tmsh::app_name\nset advanced [iapp::is ::options__advanced yes]\n\n# destination & mask array\n# array keys: $::basic__forward_all\narray set destination {\n IPv4 { destination any:any mask 0.0.0.0 }\n IPv6 { destination 0::0.any mask 0::0 }\n * { destination [iapp::destination $::basic__addr $::basic__port] \\\n mask $::basic__mask \\\n [expr { [string match \"*:*:*\" $::basic__addr] ? \"source ::/0\" : \"\" }]}\n}\n\n# PROFILES\nset use_default_profile [iapp::is ::basic__l4_profile_to_use \"/#default#\"]\n# array keys: $advanced,$use_default_profile\narray set profiles {\n 1,0 { profiles replace-all-with \\{ $::basic__l4_profile_to_use \\} }\n * { profiles replace-all-with \\{ \\\n [iapp::conf create \\\n ltm profile fastl4 ${app}_fastL4 \\\n defaults-from fastL4 \\\n reset-on-timeout disabled \\\n loose-close enabled \\\n loose-initialization enabled] \\} }\n}\n\n# VLANS\n# array keys: $::basic__vlan_listening\narray set vlans {\n enabled { vlans-enabled vlans replace-all-with \\{ $::basic__vlan_selections \\} }\n disabled { vlans-disabled vlans replace-all-with \\{ $::basic__vlan_selections \\} }\n default { vlans-disabled vlans none }\n}\n\n# RULES\nset have_irules [expr { ![iapp::is ::irules__irules \"\"] }]\n\n# array keys $advanced,$have_irules\narray set rules {\n 1,1 { rules \\{ $::irules__irules \\} }\n * { rules none }\n}\n\n# VIRTUALS\nset virtual { [iapp::conf create ltm virtual ${app}_VER_Forwarding \\\n ip-forward \\\n [iapp::substa destination(VER)] \\\n [iapp::substa profiles($advanced,$use_default_profile)] \\\n [iapp::substa vlans($::basic__vlan_listening)] \\\n [iapp::substa rules($advanced,$have_irules)]] }\n\nswitch $::basic__forward_all {\n Yes { subst [string map \"VER IPv4\" $virtual]\n subst [string map \"VER IPv6\" $virtual] }\n No { subst [string map \"VER IP\" $virtual] }\n default { subst [string map \"VER $::basic__forward_all\" $virtual] }\n}\n\niapp::template stop \n \n \n \nsection intro {\n message hello\n message check_for_updates\n}\n\nsection options {\n choice display_help display \"xxlarge\" default \"hide\"\n\n\n optional ( options.display_help == \"max\" ) {\n message display_help_max\n }\n\n choice advanced display \"xxlarge\" default \"no\"\n\n\n optional ( options.display_help == \"max\" ) {\n message conf_mode_max\n }\n}\n\nsection basic {\n choice forward_all display \"xxlarge\" default \"No\"\n\n optional ( options.display_help == \"max\" ) {\n message forward_all_max\n }\n optional ( forward_all == \"No\" ) {\n string addr default \"0.0.0.0\" required validator \"IpAddress\"\n optional ( options.display_help == \"max\" ) {\n message addr_max\n }\n string mask default \"0.0.0.0\" required validator \"IpAddress\"\n optional ( options.display_help == \"max\" ) {\n message mask_max\n }\n string port default \"0\" required validator \"PortNumber\"\n optional ( options.display_help == \"max\" ) {\n message port_max\n }\n }\n\n choice vlan_listening default \"default\" display \"xxlarge\"\n\n optional ( options.display_help == \"max\" ) {\n message vlan_listening_max\n }\n\n optional ( vlan_listening != \"default\" ) {\n multichoice vlan_selections display \"xlarge\" tcl {\n package require iapp 1.0.0\n set ::choices [iapp::get_items net vlan]\n return [iapp::safe_display ::choices]\n }\n\n optional ( vlan_listening == \"enabled\" ) {\n optional ( options.display_help == \"max\" ) {\n message vlan_selections_enabled_max\n }\n }\n\n optional ( vlan_listening == \"disabled\" ) {\n\n optional ( options.display_help == \"max\" ) {\n message vlan_selections_disabled_max\n }\n }\n }\n\n optional ( options.advanced == \"yes\" ) {\n choice l4_profile_to_use default \"/#default#\" display \"xxlarge\" tcl {\n package require iapp 1.0.0\n set ::choices \"/#default#\\n[iapp::get_items ltm profile fastl4]\"\n return [iapp::safe_display ::choices]\n }\n\n optional ( options.display_help == \"max\" ) {\n message l4_profile_to_use_max\n }\n }\n}\n\noptional ( options.advanced == \"yes\" ) {\n section irules {\n message irule_1_max\n optional ( options.display_help == \"max\" ) {\n message irule_2_max\n message irule_3_max\n }\n\n multichoice irules display \"xlarge\" tcl {\n package require iapp 1.0.0\n set ::choices [iapp::get_items -filter NAME !~ \"^_sys_\" ltm rule]\n return [iapp::safe_display ::choices]\n }\n }\n}\n\ntext {\n intro \"Welcome to the IP Forwarding template\"\n intro.hello \"Introduction\" \"This template supports configuring the BIG-IP to perform IP traffic forwarding.\"\n intro.check_for_updates \"Check for Updates\" \"Check for new versions of this template on the AskF5 Knowledge Base website (http://support.f5.com/kb/en-us/solutions/public/13000/400/sol13422.html).\"\n\n options \"Template Options\"\n options.display_help \"Do you want to see inline help?\" {\n \"Yes, show inline help\" => \"max\",\n \"No, do not show inline help\" => \"hide\"\n }\n options.display_help_max \"\" \"Inline help is available to provide contextual descriptions to aid in the completion of this configuration. Select to show or hide the inline help in this template. Important notes and warnings are always visible, no matter which selection you make here.\"\n options.advanced \"Which configuration mode do you want to use?\" {\n \"Basic - Use F5's recommended settings\" => \"no\",\n \"Advanced - Expose advanced options\" => \"yes\"\n }\n options.conf_mode_max \"\" \"This template supports twp configurations modes. Basic mode exposes the most commonly used settings, and automatically configures the rest of the options. Advanced mode allows you to review and change all settings.\"\n\n basic \"Virtual Server Questions\"\n basic.forward_all \"Should this forward all traffic not destined for virtual servers?\" {\n \"Forward all IPv4 traffic\" => \"IPv4\",\n \"Forward all IPv6 traffic\" => \"IPv6\",\n \"Forward all IPv4 and IPv6 traffic\" => \"Yes\",\n \"Forward specific traffic\" => \"No\"\n }\n basic.forward_all_max \"\" \"Choose whether to have the BIG-IP system forward all traffic that is not destined for a virtual server, or only forward traffic on a specific network, port and/or VLAN that you define. If you select Yes, the system forwards all traffic. If you select No, you must enter the address, mask, and port that define the traffic you want to forward.\"\n basic.addr \"What network address do you want to use for this virtual server?\"\n basic.addr_max \"\" \"Specifies the address of the destination network, for example, 10.0.0.0. The default 0.0.0.0 is a wildcard for all addresses, however you can still limit what is forwarded by netmask, port, or VLAN.\"\n\n basic.mask \"What is the netmask for that address?\"\n basic.mask_max \"\" \"Specifies the netmask, for example 255.255.255.0. The default 0.0.0.0 is a wildcard for any netmask.\"\n\n basic.port \"What port do you want this virtual server to use?\"\n basic.port_max \"\" \"Specifies a specific port for forwarding traffic, for example 22. The default 0 is a wildcard for any port.\"\n basic.vlan_listening \"What VLANs should this IP Forwarding virtual server listen on?\" {\n \"All VLANs\" => \"default\",\n \"Enabled on ...\" => \"enabled\",\n \"Disabled on ...\" => \"disabled\"\n }\n basic.vlan_listening_max \"\" \"You can choose to forward traffic from all VLANs or just from some of them. If you don't want to enable all VLANs, you can choose to include or exclude named VLANs and forward traffic from all of the rest.\"\n basic.vlan_selections \"On which VLAN(s) should this IP Forwarding virtual server listen?\"\n basic.vlan_selections_enabled_max \"\" \"Select the VLANs from which traffic will be forwarded.\"\n\n basic.vlan_selections_disabled_max \"\" \"Select the VLANs from which traffic NOT will be forwarded.\"\n basic.l4_profile_to_use \"What Fast L4 profile do you want to use?\" {\"Use F5's recommended Fast L4 profile\" => \"/#default#\"}\n\n basic.l4_profile_to_use_max \"\" \"If you created a custom Fast L4 profile, you can select it from the list. This is not required for most purposes, and only necessary if you need to replace the default Fast L4 profile functionality.\"\n\n irules \"iRules\"\n irules.irules \"Do you want to add any custom iRules to this configuration?\"\n\n irules.irule_1_max \"WARNING\" \"Improper use or misconfigurations of an iRule can result in unwanted application behavior and poor performance of your BIG-IP system. For this reason we recommended you verify the impact of an iRule prior to deployment in a production environment.\"\n\n irules.irule_2_max \"\" \"The BIG-IP system supports a scripting language to allow an administrator to instruct the system to intercept, inspect, transform, direct and track inbound or outbound application traffic. An iRule contains the set of instructions the system uses to process data flowing through it, either in the header or payload of a packet.\"\n\n irules.irule_3_max \"\" \"Correct event priority is critical when assigning multiple iRules. For more information about iRule event priority, see https://devcentral.f5.com/s/wiki/iRules.priority.ashx\"\n} \n \n \n To get started with modifying this template, we want to create a copy. \n In the GUI, click iApps->Templates->f5.ip_forwarding, and then at the very bottom, click copy. At the iApps >> Clone Template screen, change the Template Name(s) field to the name you want your template to have. I called mine f5_stripped.ip_forwarding. You can edit from here, but at this step I just clicked Finish before re-entering to do the editing work. Back at the iApps template listing, you should see your new iApp, which other than title, should be the same as the original, with the exception of validation (which should now read None.) Click into your new template and now we'll get to work editing. \n Presentation \n In the presentation section, we can weed out the basic/advanced section since we aren't allowing profile or iRule manipulation (lines 13-19.) Next we'll eliminate the forward_all option since we're not giving them the choice of of IPv4/IPv6 defaults or all networks (lines 23-28; 41.) Moving on, we'll trim the port section (lines 37-40.) Finally, we'll pull the advanced section altogether, which deals with the profiles and iRules (lines 69-96.) \n In the text area of the presentation, we pull out all the unnecessary text now that those GUI objects will not be present (lines 110-14; 117-123; 130-131; 137; 142-153.) \n This is best shown in the following images. \n \n \n Implementation \n The changes in the implementation section follow suit. We remove the arrays for destination (lines 7-15) and profiles (lines 17-29,) as well as the army for rules (lines 38-46,) and the switch for the type of forwarding virtual this will be since we're forcing end users to specify the networks (lines 56-61.) The only thing we need to slightly modify is the virtuals section (lines 48-54.) Here, we are removing the need for the variable and just creating the virtual server with the  iapp::conf command. We are not passing a port from the iApp, so we use :any here (line 15) and then use the array as is for vlans to configure those. Screenshot to show these updates is below. \n \n Easy enough! Updated iApp code is below. \n Implementation Presentation \n \n \npackage require iapp 1.0.0\niapp::template start\n\nset app $tmsh::app_name\n\n# VLANS\n# array keys: $::basic__vlan_listening\narray set vlans {\n enabled { vlans-enabled vlans replace-all-with \\{ $::basic__vlan_selections \\} }\n disabled { vlans-disabled vlans replace-all-with \\{ $::basic__vlan_selections \\} }\n default { vlans-disabled vlans none }\n}\niapp::conf create ltm virtual ${app}_IPv4_Forwarding \\\n ip-forward \\\n destination $::basic__addr:any mask $::basic__mask \\\n [iapp::substa vlans($::basic__vlan_listening)]\n\niapp::template stop \n \n \n \nsection intro {\n message hello\n message check_for_updates\n}\n\nsection options {\n choice display_help display \"xxlarge\" default \"hide\"\n optional ( options.display_help == \"max\" ) {\n message display_help_max\n }\n}\n\nsection basic {\n\n string addr default \"0.0.0.0\" required validator \"IpAddress\"\n optional ( options.display_help == \"max\" ) {\n message addr_max\n }\n string mask default \"0.0.0.0\" required validator \"IpAddress\"\n optional ( options.display_help == \"max\" ) {\n message mask_max\n }\n\n\n choice vlan_listening default \"default\" display \"xxlarge\"\n\n optional ( options.display_help == \"max\" ) {\n message vlan_listening_max\n }\n\n optional ( vlan_listening != \"default\" ) {\n multichoice vlan_selections display \"xlarge\" tcl {\n package require iapp 1.0.0\n set ::choices [iapp::get_items net vlan]\n return [iapp::safe_display ::choices]\n }\n\n optional ( vlan_listening == \"enabled\" ) {\n optional ( options.display_help == \"max\" ) {\n message vlan_selections_enabled_max\n }\n }\n\n optional ( vlan_listening == \"disabled\" ) {\n\n optional ( options.display_help == \"max\" ) {\n message vlan_selections_disabled_max\n }\n }\n }\n}\n\ntext {\n intro \"Welcome to the IP Forwarding template\"\n intro.hello \"Introduction\" \"This template supports configuring the BIG-IP to perform IP traffic forwarding.\"\n intro.check_for_updates \"Check for Updates\" \"Check for new versions of this template on the AskF5 Knowledge Base website (http://support.f5.com/kb/en-us/solutions/public/13000/400/sol13422.html).\"\n\n options \"Template Options\"\n options.display_help \"Do you want to see inline help?\" {\n \"Yes, show inline help\" => \"max\",\n \"No, do not show inline help\" => \"hide\"\n }\n options.display_help_max \"\" \"Inline help is available to provide contextual descriptions to aid in the completion of this configuration. Select to show or hide the inline help in this template. Important notes and warnings are always visible, no matter which selection you make here.\"\n\n basic \"Virtual Server Questions\"\n basic.addr \"What network address do you want to use for this virtual server?\"\n basic.addr_max \"\" \"Specifies the address of the destination network, for example, 10.0.0.0. The default 0.0.0.0 is a wildcard for all addresses, however you can still limit what is forwarded by netmask, port, or VLAN.\"\n\n basic.mask \"What is the netmask for that address?\"\n basic.mask_max \"\" \"Specifies the netmask, for example 255.255.255.0. The default 0.0.0.0 is a wildcard for any netmask.\"\n\n basic.vlan_listening \"What VLANs should this IP Forwarding virtual server listen on?\" {\n \"All VLANs\" => \"default\",\n \"Enabled on ...\" => \"enabled\",\n \"Disabled on ...\" => \"disabled\"\n }\n basic.vlan_listening_max \"\" \"You can choose to forward traffic from all VLANs or just from some of them. If you don't want to enable all VLANs, you can choose to include or exclude named VLANs and forward traffic from all of the rest.\"\n basic.vlan_selections \"On which VLAN(s) should this IP Forwarding virtual server listen?\"\n basic.vlan_selections_enabled_max \"\" \"Select the VLANs from which traffic will be forwarded.\"\n\n basic.vlan_selections_disabled_max \"\" \"Select the VLANs from which traffic NOT will be forwarded.\"\n} \n \n \n With the finished stripped version of the ip forwarding iApp, we can now deploy the template in a new application service. \n \n \n \n Join us for the next article in this series, where we'll tackle writing an iApp from scratch! ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"17307","kudosSumWeight":0,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwNzctODUwMGk5N0NBQjEzRDg0MDYxMUU1?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwNzctMTU2MzNpMkY2RTk4MDYyNDAzQzk3OA?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwNzctOTE4MGk3NkFEQjI1QjRBM0MxNkNF?revision=2\"}"}}],"totalCount":3,"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:289122":{"__typename":"Conversation","id":"conversation:289122","topic":{"__typename":"TkbTopicMessage","uid":289122},"lastPostingActivityTime":"2023-06-05T22:51:30.762-07:00","solved":false},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItOTgxMmkwRkMyMEZBN0QxRjRBNjg5?revision=2\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItOTgxMmkwRkMyMEZBN0QxRjRBNjg5?revision=2","title":"0151T000003d6rlQAA.png","associationType":"BODY","width":646,"height":443,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItMzQyN2k0OUNDNEZEOEM4QTI3RDI0?revision=2\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItMzQyN2k0OUNDNEZEOEM4QTI3RDI0?revision=2","title":"0151T000003d6rmQAA.png","associationType":"BODY","width":542,"height":312,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItODEwN2k4OEU5NzAzRkEwMzczQUIw?revision=2\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItODEwN2k4OEU5NzAzRkEwMzczQUIw?revision=2","title":"0151T000003d6rnQAA.png","associationType":"BODY","width":566,"height":334,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItMTc4MWkxNTg0RjAwMTY4RDMxMzkx?revision=2\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItMTc4MWkxNTg0RjAwMTY4RDMxMzkx?revision=2","title":"0151T000003d6roQAA.png","associationType":"BODY","width":410,"height":280,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItMTEzMjhpQkVDQjJCMEJFNEJGOTQ3QQ?revision=2\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItMTEzMjhpQkVDQjJCMEJFNEJGOTQ3QQ?revision=2","title":"0151T000003d6rpQAA.png","associationType":"BODY","width":450,"height":302,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItNjk4NGlEMEI3OEM5MDJFMUFBQ0M2?revision=2\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItNjk4NGlEMEI3OEM5MDJFMUFBQ0M2?revision=2","title":"0151T000003d6rqQAA.png","associationType":"BODY","width":433,"height":261,"altText":null},"TkbTopicMessage:message:289122":{"__typename":"TkbTopicMessage","subject":"Getting Started with iApps: Best Practices","conversation":{"__ref":"Conversation:conversation:289122"},"id":"message:289122","revisionNum":2,"uid":289122,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:51154"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":1065},"postTime":"2016-06-24T15:00:00.000-07:00","lastPublishTime":"2023-06-05T22:51:30.762-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" In this final article in the Getting Started with iApps series, we’ll ship gears from concepts and code to best practices and lessons learned. \n\n Start Small \n\n As stated earlier--iApps are complex. If you don’t know tmsh, or better, tmsh scripting, I’d recommend spending some time getting comfortable at the command line writing scripts before moving to an iApp. Once you have the foundational tmsh skills, start with a simple task like what we covered in the modifying and creating articles in this series. After the pieces start to fit together more clearly, expand from there. \n\n Start Basic \n\n I mentioned the iApp utility package in the previous article. It’s available and it’s awesome. But it also abstracts some of the work that might confuse what’s actually happening in the iApp. I’d recommend you avoid the utility package while you are learning, then once you’re comfortable, convert your test work to the utility package. Afterwards, starting with the utility package unlocks a lot of functionality that will save you time and headaches. \n\n Attributes \n\n This is a small but important section of the iApp. When developing an iApp, there may be features that exist on your version that either didn’t exist or changed significantly from previous or later versions. Setting the minimum and maximum versions where applicable might save you or others in the event of upgrades or imports. Also, establishing the required modules up front is important, so don’t forget this step. \n\n Presentation \n\n This is the user interface for those deploying your template, so it’s important to consider not only the required information, but also the layout. Some best practices for the template design: \n\n Use a question and answer format Be simple Be clear Be complete Follow your organization’s nomenclature \n\n Gotcha: You may be tempted to expose only a few settings on any particular configuration object, leaving the remaining settings default. But a default when creating objects via the GUI is not necessarily the same default when creating them via tmsh. Example: a virtual server created via the GUI defaults to the tcp profile, but creating a virtual server via tmsh defaults to the fastL4 profile. \n\n Make sure to use the layout elements to your advantage. Use the section element to group like features/functionality in your iApp. \n\n \n\n Hide stuff that isn't required for particular deployments by using the optional element. This makes readability much better \n\n \n\n Underscores in section variable names are possible, but discouraged. Yes, I broke this rule in the creating an iApp article yesterday! The reason is because the section.variable on the implementation ends up section__variable (double underscore) and if your section also has an underscore, it makes it easy to overlook the differences. \n\n Use validators for input fields where they are supported. These are some common validators: \n\n Number:  Any integer NonNegativeNumber: Any integer >= 0 IpAddress:  * for all addresses, or an IPv4 or IPv6 address PortNumber: * for all ports, or an integer value between 0 and 65535 inclusive FQDN: RFC 1034 compliant domain name IpOrFQDN: IPv4, IPv6, or an RFC 1034 complaint domain name. * not allowed \n\n Gotcha: validators are not available with the edit choice element, so make sure to add validation on the implementation section for the values returned from these elements. \n\n Also very helpful: you can display user-friendly wording while setting a different value that is passed on to the implementation. This is nice for things like the load balancing method, where least-connections-member isn’t awesome to look at, but is the required text string for the tmsh::pool create/modify command. \n\n \n\n Finally, you can test all your variable setting and such by using the  puts  command in the implementation section that will log all your values from the presentation section. This information is useful for debugging and is dumped in the /var/tmp/scriptd.out file for review. Examples: \n\n \nputs $::basic_info__validation\nputs $::basic_info__key\nputs $::basic_info__rules\n\n[root@ltm3:Active:Standalone] config # tail -f /var/tmp/scriptd.out\n\nSignature\ndefault.key\ntest1 test2 \n\n Implementation \n\n The implementation section is pretty much a tmsh script, without the required skeleton. the hierarchy of tmsh, for those not well versed, looks like this: \n\n \n\n The general syntax of tmsh commands is: \n\n tmsh <command> <module> [<submodule>] <component> <parameters> \n\n The syntax varies slightly depending on where the commands are issued. For example: \n\n Location where command is run Syntax tmsh root (tmos) # create /ltm virtual virtual_name... virtual server component of tmsh (tmos.ltm.virtual) # create virtual_name... linux bash prompt config # tmsh create /ltm virtual virtual_name... iApp implementation section tmsh::create \"/ltm virtual virtual_name...\" iapp::conf create ltm virtual virtual_name... \n\n In addition to the declared variables from the presentation section, you can set variables in the implementation section as well. This  foreach  loop shows the use of a local variable (obj) and the presentation declared variable ($::basic_info__rules) \n\n \nforeach obj $::basic_info__rules {\n exec \"tmsh\" \"generate\" \"ltm\" \"rule\" $obj \"checksum\"\n} \n\n There’s also  tmsh::app_name  which stores the name of your application service. When creating objects, it’s helpful to name them with your application name as a header. This can be done like so: \n\n \nset app $tmsh::app_name\ntmsh::create “/ltm pool ${app}_MyPool ... \n\n The { } brackets are there so the interpreter to only interprets app when doing the variable lookup. There are a lot more general tcl best practices, but those are out of scope for this article. \n\n Reentrancy \n\n iApps were created with serving an application over time, not just a Ron Popeil “set it and forget it” experience. That’s more the point of a wizard. This presents a challenge, as you need to create objects initially, but when you reconfigure your iApp, you’re modifying existing objects. In tmsh, this is problematic: if you try to create an existing object, it’ll complain. Why does this work in an iApp then?  \n\n The answer is, through a process called mark-and-sweep. When the iApp user selects an existing application service and clicks the Reconfigure tab, they are reentering your template and its code. They can keep and/or change their responses to the presentation section prompts. If they make changes that result in a new configuration, the mark-and-sweep process is designed to help transform the old configuration to the new configuration. \n\n On reentrancy, the code in the template’s implementation section is re-executed. Conditional code is executed based on the variable values set by you or by the user’s responses. Any tmsh::create commands that are “touched” are marked and converted to tmsh::modify commands. Any objects that are “untouched” are deleted in the sweep. \n\n \n\n\n\n Strict Updates \n\n Strike updates protect all the objects generated by an iApp. So if you created an iApp that owns the pool app_myPool, that pool cannot be modified outside of the iApp. This is good when a lot of cooks are in the kitchen and someone inadvertently tries to delete your pool. Because the iApp owns it, that attempt will fail. There are situations where you might be tempted to disable the strict updates, but the better option is to modify the template. If you do disable the strict updates, redeploying the iApp will sometimes overwrite the out-of-band changes. Sometimes. The outcome is not so easily predicted. \n\n To illustrate the difficulties, consider two scenarios. \n\n Changing an HTTP Profile \n\n In this scenario, a simple iApp accepts 2 inputs and constructs a virtual server with a custom HTTP profile: \n\n \npresentation {\n section virtual {\n string ip required\n choice xff { “enabled”, “disabled” }\n }\n}\nimplementation {\n tmsh::create ltm profile http ${tmsh::app_name}_http \\\n insert-xforwarded-for $::virtual__xff\n tmsh::create ltm virtual ${tmsh::app_name}_vs \\\n destination $::virtual__ip:80 \\\n profiles add \\{ ${tmsh::app_name}_http \\}\n} \n\n Suppose you deploy this iApp with X-Forwarded-For enabled, then disable strict-updates and edit the HTTP profile directly as shown: \n\n \n\n Now, re-enter and re-deploy the iApp without changing any inputs. What is the result? You might expect your manual customization of response chunking to remain in place, because there is no mention of response chunking in the iApp code. In this case, however, iApp re-deployment causes chunking to be set back to its default value. \n\n Disabling Virtual Server Address Translation \n\n In this scenario, you need to disable address translation on a virtual server, which was not possible in the iApp. Disable address translation, then re-enter and re-deploy the iApp again. What is the result this time? You might expect your customization to be overwritten as it was in the previous example. In this case, however, address translation remains disabled. The TMSH “modify” command does not handle defaults consistently across all key-value pairs. This makes tampering with a strictly-enforced configuration especially hazardous. \n\n Conclusion \n\n iApps are amazingly powerful tools for taking a lot of the guesswork and potential errors out of application deployments. There is so much more to iApps than we could possibly cover in this five article series, but the intention this week was not to make you experts; merely to expose you to the concepts and get your feet wet with some examples. The great thing about iApps is the are not compiled code: all of them, whether F5 supported, F5 contributed, or community contributed, can be analyzed and repurposed for your use.  ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"9912","kudosSumWeight":0,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItOTgxMmkwRkMyMEZBN0QxRjRBNjg5?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItMzQyN2k0OUNDNEZEOEM4QTI3RDI0?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItODEwN2k4OEU5NzAzRkEwMzczQUIw?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItMTc4MWkxNTg0RjAwMTY4RDMxMzkx?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItMTEzMjhpQkVDQjJCMEJFNEJGOTQ3QQ?revision=2\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDY","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkxMjItNjk4NGlEMEI3OEM5MDJFMUFBQ0M2?revision=2\"}"}}],"totalCount":6,"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:288454":{"__typename":"Conversation","id":"conversation:288454","topic":{"__typename":"TkbTopicMessage","uid":288454},"lastPostingActivityTime":"2020-12-14T08:33:54.000-08:00","solved":false},"User:user:283810":{"__typename":"User","uid":283810,"login":"Thomas_Schocka1","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/m_assets/avatars/default/avatar-3.svg?time=0"},"id":"user:283810"},"TkbTopicMessage:message:288454":{"__typename":"TkbTopicMessage","subject":"F5 Automated Backups - The Right Way","conversation":{"__ref":"Conversation:conversation:288454"},"id":"message:288454","revisionNum":1,"uid":288454,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:283810"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":9382},"postTime":"2014-03-12T20:34:00.000-07:00","lastPublishTime":"2014-03-12T20:34:00.000-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Hi all, \n\n   \n\n Often I've been scouring the devcentral fora and codeshares to find that one piece of handywork that will drastically simplify my automated backup needs on F5 devices. Based on the works of Jason Rahm in his post \"Third Time's the Charm: BIG-IP Backups Simplified with iCall\" on the 26th of June 2013, I went ahead and created my own iApp that pretty much provides the answers for all my backup-needs. \n\n Here's a feature list of this iApp: \n\n It allows you to choose between both UCS or SCF as backup-types. (whilst providing ample warnings about SCF not being a very good restore-option due to the incompleteness in some cases) It allows you to provide a passphrase for the UCS archives (the standard GUI also does this, so the iApp should too) It allows you to not include the private keys (same thing: standard GUI does it, so the iApp does it too) It allows you to set a Backup Schedule for every X minutes/hours/days/weeks/months or a custom selection of days in the week It allows you to set the exact time, minute of the hour, day of the week or day of the month when the backup should be performed (depending on the usefulness with regards to the schedule type) It allows you to transfer the backup files to external devices using 4 different protocols, next to providing local storage on the device itself\n SCP (username/private key without password) SFTP (username/private key without password) FTP (username/password) SMB (using smbclient, with username/password) Local Storage (/var/local/ucs or /var/local/scf) \n It stores all passwords and private keys in a secure fashion: encrypted by the master key of the unit (f5mku), rendering it safe to store the backups, including the credentials off-box It has a configurable automatic pruning function for the Local Storage option, so the disk doesn't fill up (i.e. keep last X backup files) It allows you to configure the filename using the date/time wildcards from the tcl [clock] command, as well as providing a variable to include the hostname It requires only the WebGUI to establish the configuration you desire It allows you to disable the processes for automated backup, without you having to remove the Application Service or losing any previously entered settings For the external shellscripts it automatically generates, the credentials are stored in encrypted form (using the master key) It allows you to no longer be required to make modifications on the linux command line to get your automated backups running after an RMA or restore operation It cleans up after itself, which means there are no extraneous shellscripts or status files lingering around after the scripts execute \n\n I wasn't able to upload the iApp template to this article, so I threw it on pastebin: http://pastebin.com/YbDj3eMN \n\n   \n\n Enjoy! \n\n Thomas Schockaert ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"2857","kudosSumWeight":0,"repliesCount":79,"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:284751":{"__typename":"Conversation","id":"conversation:284751","topic":{"__typename":"TkbTopicMessage","uid":284751},"lastPostingActivityTime":"2020-11-23T10:24:12.000-08:00","solved":false},"User:user:322278":{"__typename":"User","uid":322278,"login":"PeteWhite","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/m_assets/avatars/default/avatar-5.svg?time=0"},"id":"user:322278"},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODQ3NTEtMTIzMTlpODcxNzhFOUFCQkI3RUFDNQ?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODQ3NTEtMTIzMTlpODcxNzhFOUFCQkI3RUFDNQ?revision=1","title":"0151T000003pz6RQAQ.jpg","associationType":"BODY","width":1110,"height":438,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODQ3NTEtNjk0OWkwMDQ4NDNEMzQ3MTM3QkQ1?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODQ3NTEtNjk0OWkwMDQ4NDNEMzQ3MTM3QkQ1?revision=1","title":"0151T000003pzKTQAY.jpg","associationType":"BODY","width":1623,"height":1039,"altText":null},"TkbTopicMessage:message:284751":{"__typename":"TkbTopicMessage","subject":"DNS over HTTPS Resolution","conversation":{"__ref":"Conversation:conversation:284751"},"id":"message:284751","revisionNum":1,"uid":284751,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:322278"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":1270},"postTime":"2020-11-23T10:24:12.000-08:00","lastPublishTime":"2020-11-23T10:24:12.000-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Introduction \n\n   \n\n I work in the EMEA Professional Services team and in this article I will walk you through a recent solution which I provided to support the F5 Sales team for a Service Provider. You can see the finished iApp here which took a few days of work spread over a few months. \n\n   \n\n This solution is to provide DNS over HTTP resolution - F5 has this as a feature soon to be released but in the meantime we needed a working solution. \n\n   \n\n Development \n\n I started by looking at the RFC ( https://tools.ietf.org/html/rfc8484 ) to work out what was required and realised that this has two methods - GET and POST, it gives examples of the payload and response so I put together a simple lab and proof of concept. This used curl to send the data - both methods send a DNS wire-format packet, GET base64url-encodes it and sends it as a parameter while POST sends it in the payload directly. \n\n   \n\n I decided it would be simplest to use an iRule with sideband to a local virtual server which would in turn send the traffic to the backend server. Below is the simple pseudocode I created to guide me: \n\n   \n\n \nwhen HTTP_REQUEST\n if URI \n if method == POST\n collect payload\n if method == GET\n decode payload\n send payload via sideband\n return response\nendwhen\nwhen HTTP_DATA\n send payload via sideband\n return response\nendwhen\n \n\n   \n\n From this you can see that I have 'send payload via sideband' in two places. I like to follow the DRY principle so i immediately thought about procedures in later versions. \n\n   \n\n I have used sideband a number of times before but i reviewed how it works in terms of destination and source address at https://clouddocs.f5.com/api/irules/SIDEBAND.html . For base64url, I decided to start with the built-in base64 decoding function ( https://clouddocs.f5.com/api/irules/b64decode.html ) and use string map to change the erroneous characters. \n\n   \n\n \n\n   \n\n See my lab configuration below with my first version of the iRule: \n\n   \n\n \n[root@DoH-bigip1:Active:Standalone] config # tmsh list ltm pool\nltm pool dns {\n    members {\n        server-1:domain {\n            address 10.20.20.6\n        }\n    }\n}\n[root@DoH-bigip1:Active:Standalone] config # tmsh list ltm virtual\nltm virtual DoH {\n    creation-time 2020-05-04:03:17:08\n    destination 10.10.10.10:https\n    ip-protocol tcp\n    last-modified-time 2020-05-04:03:33:22\n    mask 255.255.255.255\n    profiles {\n        clientssl-insecure-compatible {\n            context clientside\n        }\n        http { }\n        tcp { }\n    }\n    rules {\n        DoH\n    }\n    serverssl-use-sni disabled\n    source 0.0.0.0/0\n    translate-address enabled\n    translate-port enabled\n    vlans {\n        External\n    }\n    vlans-enabled\n    vs-index 4\n}\nltm virtual dns-tcp {\n    creation-time 2020-05-04:03:15:46\n    destination 10.10.10.10:domain\n    ip-protocol tcp\n    last-modified-time 2020-05-04:03:15:46\n    mask 255.255.255.255\n    pool dns\n    profiles {\n        dns { }\n        tcp { }\n    }\n    serverssl-use-sni disabled\n    source 0.0.0.0/0\n    source-address-translation {\n        type automap\n    }\n    translate-address enabled\n    translate-port enabled\n    vlans {\n        External\n    }\n    vlans-enabled\n    vs-index 3\n}\nltm virtual dns-udp {\n    creation-time 2020-05-04:03:14:25\n    destination 10.10.10.10:domain\n    ip-protocol udp\n    last-modified-time 2020-05-04:03:14:25\n    mask 255.255.255.255\n    pool dns\n    profiles {\n        dns { }\n        udp { }\n    }\n    rules {\n        dns-log\n    }\n    serverssl-use-sni disabled\n    source 0.0.0.0/0\n    source-address-translation {\n        type automap\n    }\n    translate-address enabled\n    translate-port enabled\n    vlans {\n        External\n    }\n    vlans-enabled\n    vs-index 2\n}\nltm rule DoH {\nwhen RULE_INIT {\n    set static::sideband_virtual_server \"/Common/dns-udp\"\n}\nwhen HTTP_REQUEST {\n    # https://tools.ietf.org/html/rfc8484\n    if { [HTTP::uri] == \"/dns-query\" } {\n        if { (([HTTP::method] equals \"POST\") and (([HTTP::header \"accept\"] equals \"application/dns-message\") or ([HTTP::header \"content-type\"] equals \"application/dns-message\"))) } { \n            if {[HTTP::header exists \"Content-Length\"] && [HTTP::header \"Content-Length\"] <= 65535 && [HTTP::header \"Content-Length\"] > 0} { \n                log local0.debug \"Content-Length [HTTP::header value \"Content-Length\"]\"\n                HTTP::collect [HTTP::header value \"Content-Length\"] \n            } else { \n                HTTP::collect 100\n            } \n        } else {\n            HTTP::respond 415 content \"Unsupported Media Type\"\n        }\n    } else {\n        HTTP::respond 404\n    }\n}\n\nwhen HTTP_REQUEST_DATA {\n    # Use sideband\n    set conn_id [connect -protocol UDP -timeout 100 -idle 30 -status conn_status /Common/dns-udp]\n    log local0.debug \"Connection status: $conn_status\"\n    log local0.debug \"Payload B64: [b64encode [HTTP::payload]]\"\n    set send_bytes [send -timeout 100 -status send_status $conn_id [HTTP::payload]]\n    log local0.debug \"send_status: $send_status\"\n    recv -timeout 100 -peek -status recv_status $conn_id result\n    log local0.debug \"status: $recv_status Result B64: [b64encode $result]\"\n    HTTP::respond 200 content $result noserver content-type application/dns-message vary Accept-Encoding content-length [string length $result] \n}\n}\n\nltm rule dns-log {\nwhen DNS_REQUEST {\nlog local0.debug \"[DNS::question name] [DNS::question class] [DNS::question type]\"\n}\nwhen DNS_RESPONSE {\nset rrs [DNS::answer]\n     foreach rr $rrs {\n         log local0. \"[DNS::rdata $rr]\"\n     }\n}\n}\n \n\n   \n\n I tested this setup using the following procedure: \n\n   \n\n Create DNS wire request in binary file \n\n \necho \"00 00 01 00 00 01 00 00 00 00 00 00 03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 01 00 01\"|xxd -r -p >example_req\n \n\n   \n\n Perform curl request \n\n \ncurl -k -H 'content-type: application/dns-message' --data-binary @example_req -o output_file https://10.10.10.10/dns-query\n \n\n   \n\n Inspect output file \n\n \nroot@DoH-xubuntu-desktop1:~# xxd output_file\n00000000: 0000 8580 0001 0001 0001 0002 0377 7777 .............www\n00000010: 0765 7861 6d70 6c65 0363 6f6d 0000 0100 .example.com....\n00000020: 01c0 0c00 0100 0100 093a 8000 0401 0203 .........:......\n00000030: 04c0 1000 0200 0100 093a 8000 0b09 6c6f .........:....lo\n00000040: 6361 6c68 6f73 7400 c03d 0001 0001 0009 calhost..=......\n00000050: 3a80 0004 7f00 0001 c03d 001c 0001 0009 :........=......\n00000060: 3a80 0010 0000 0000 0000 0000 0000 0000 :...............\n00000070: 0000 0001                               ....\n \n\n   \n\n My BIG-IP logs: \n\n   \n\n \nMay 4 05:49:12 DoH-bigip1 debug tmm[22188]: Rule /Common/DoH <HTTP_REQUEST>: Content-Length 33\nMay 4 05:49:12 DoH-bigip1 debug tmm[22188]: Rule /Common/DoH <HTTP_REQUEST_DATA>: Doing sideband\nMay 4 05:49:12 DoH-bigip1 debug tmm[22188]: Rule /Common/DoH <HTTP_REQUEST_DATA>: Connection status: connected\nMay 4 05:49:12 DoH-bigip1 debug tmm[22188]: Rule /Common/DoH <HTTP_REQUEST_DATA>: Payload B64: AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB\nMay 4 05:49:12 DoH-bigip1 debug tmm[22188]: Rule /Common/DoH <HTTP_REQUEST_DATA>: send_status: sent\nMay 4 05:49:12 DoH-bigip1 debug tmm[22188]: Rule /Common/dns-log <DNS_REQUEST>: www.example.com IN A\nMay 4 05:49:12 DoH-bigip1 info tmm[22188]: Rule /Common/dns-log <DNS_RESPONSE>: 1.2.3.4\nMay 4 05:49:12 DoH-bigip1 debug tmm[22188]: Rule /Common/DoH <HTTP_REQUEST_DATA>: status: received Result B64: AACFgAABAAEAAQACA3d3dwdleGFtcGxlA2NvbQAAAQABwAwAAQABAAk6gAAEAQIDBMAQAAIAAQAJOoAACwlsb2NhbGhvc3QAwD0AAQABAAk6gAAEfwAAAcA9ABwAAQAJOoAAEAAAAAAAAAAAAAAAAAAAAAE=\n \n\n   \n\n I then added GET resolution: \n\n   \n\n \nwhen RULE_INIT {\n   set static::sideband_virtual_server \"/Common/dns-udp\"\n}\n\nwhen HTTP_REQUEST {\n   # https://tools.ietf.org/html/rfc8484\n   if { [HTTP::path] == \"/dns-query\" } {\n       if { (([HTTP::method] equals \"POST\") and (([HTTP::header \"accept\"] equals \"application/dns-message\") or ([HTTP::header \"content-type\"] equals \"application/dns-message\"))) } { \n           if {[HTTP::header exists \"Content-Length\"] && [HTTP::header \"Content-Length\"] <= 65535 && [HTTP::header \"Content-Length\"] > 0} { \n               log local0.debug \"Content-Length [HTTP::header value \"Content-Length\"]\"\n               HTTP::collect [HTTP::header value \"Content-Length\"] \n           } else { \n               HTTP::collect 100\n           } \n       } elseif { [HTTP::method] equals \"GET\" && [URI::query [HTTP::uri] dns] != \"\" } {\n           set queryname [b64decode [URI::query [HTTP::uri] dns] ]\n           \n           log local0.debug \"QNAME: $queryname\"\n           set header [ binary format c12 \"0 0 1 0 0 1 0 0 0 0 0 0\" ]\n           # FORMAT QNAME\n           set name \"\"\n           foreach { field } [split $queryname .] {\n               set strlen [ string length $field ]\n               append name [ binary format c $strlen ]\n               append name [ binary format a* $field ]\n           }\n           # QNAME ends with NULL\n           append name [ binary format c \"0\" ]\n           \n           # QTYPE: A\n           append name [ binary format S 1 ]\n           # QCLASS IN\n           append name [ binary format S 1 ]\n           \n           binary scan \"$header$name\" H* p\n           log local0.debug \"Payload: $p\"\n           set conn_id [connect -protocol UDP -timeout 100 -idle 30 -status conn_status /Common/dns-udp]\n           log local0.debug \"Connection status: $conn_status\"\n           log local0.debug \"Payload B64: [b64encode [HTTP::payload]]\"\n           set send_bytes [send -timeout 100 -status send_status $conn_id [binary format H* $p] ]\n           log local0.debug \"send_status: $send_status\"\n           recv -timeout 100 -peek -status recv_status $conn_id result\n           log local0.debug \"status: $recv_status Result B64: [b64encode $result]\"\n           HTTP::respond 200 content $result noserver content-type application/dns-message vary Accept-Encoding content-length [string length $result] \n       \n       } else {\n           HTTP::respond 415 content \"Unsupported Media Type\" \n       }\n   } else {\n       HTTP::respond 404\n   }\n}\nwhen HTTP_REQUEST_DATA {\n   # Use sideband\n   set conn_id [connect -protocol UDP -timeout 100 -idle 30 -status conn_status /Common/dns-udp]\n   log local0.debug \"Connection status: $conn_status\"\n   log local0.debug \"Payload B64: [b64encode [HTTP::payload]]\"\n   set send_bytes [send -timeout 100 -status send_status $conn_id [HTTP::payload]]\n   log local0.debug \"send_status: $send_status\"\n   recv -timeout 100 -peek -status recv_status $conn_id result\n   log local0.debug \"status: $recv_status Result B64: [b64encode $result]\"\n   HTTP::respond 200 content $result noserver content-type application/dns-message vary Accept-Encoding content-length [string length $result] \n}\n \n\n   \n\n Tested below: \n\n   \n\n \nroot@DoH-xubuntu-desktop1:~# curl -k -H 'content-type: application/dns-message' -o output_file_get https://10.10.10.10/dns-query?dns=d3d3LmV4YW1wbGUuY29t\n % Total   % Received % Xferd Average Speed  Time   Time    Time Current\n                                Dload Upload  Total  Spent   Left Speed\n100  116 100  116   0    0   974     0 --:--:-- --:--:-- --:--:--  974\n \n\n   \n\n If you are sharp-eyed you will notice that i made a mistake on this - I only sent the encoded name, not an encoded DNS wireformat packet. \n\n   \n\n For reference, see below my notes on how to create the DNS wireformat packet for www.example.com ( which the RFC uses ): \n\n   \n\n 00 00 01 00 00 01 00 00 00 00 00 00 03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 01 00 01 \n\n DNS Header \n\n ID = 00 00 \n\n Recursion Available = 01 00 \n\n QCOUNT = 00 01 \n\n ANSCOUT = 00 00 \n\n NSCOUNT = 00 00 \n\n ARCOUNT = 00 00 \n\n   \n\n DNS Query \n\n www \n\n LENGTH = 03 \n\n FIELD = 77 77 77 ( www ) \n\n   \n\n example \n\n LENGTH = 07 ( 7 octets ) \n\n FIELD = 65 78 61 6d 70 6c 65 ( example ) \n\n   \n\n com \n\n LENGTH = 03 \n\n FIELD = 63 6f 6d ( com ) \n\n   \n\n NULL LABEL = 00 ( end of question name ) \n\n   \n\n QTYPE = 00 01 = A \n\n QCLASS = 00 01 = IN \n\n   \n\n   \n\n I modified this to create a v1.0 which worked adequately as a proof of concept. In testing, I saw the following statistics for 1000 consecutive POST requests: \n\n   \n\n \n[root@DoH-bigip1:Active:Standalone] config # tmsh show ltm rule DoH\n\n---------------------------------\nLtm::Rule Event: DoH:HTTP_REQUEST\n---------------------------------\nPriority                   500\nExecutions\n Total                   1.0K\n Failures                   0\n Aborts                     0\nCPU Cycles on Executing\n Average               278.8K\n Maximum                 6.1M\n Minimum               147.8K\n\n--------------------------------------\nLtm::Rule Event: DoH:HTTP_REQUEST_DATA\n--------------------------------------\nPriority                   500\nExecutions\n Total                   1.0K\n Failures                   0\n Aborts                     0\nCPU Cycles on Executing\n Average               644.3K\n Maximum                 6.3M\n Minimum               391.1K\n\n------------------------------\nLtm::Rule Event: DoH:RULE_INIT\n------------------------------\nPriority                500\nExecutions\n Total                   0\n Failures                0\n Aborts                  0\nCPU Cycles on Executing\n Average                 0\n Maximum                 0\n Minimum                 0\n \n\n   \n\n   \n\n Over the subsequent weeks and months, my colleagues gave me feedback on issues or suggestions, and i created a GUI for the iRule with an iApp. \n\n   \n\n The first issue was that it kept generating errors in the base64 decoding command. This is because base64 and base64url are subtly different. To cure this problem, I spent a few hours looking in detail at when it fails and what the difference between base64 and base64url would be, along with some detailed reading. The upshot is that I added a b64urldecode procedure to handle this: \n\n   \n\n \nproc b64urldecode { str } {\n    # Procedure to perform base64url decoding\n    set str [ string map { - + _ \\/ } $str]\n    set pad [expr {[string length $str] % 4}]\n    if { $pad != 0} {\n        append str [string repeat = [expr {4 - $pad}]]\n    }\n    \n    if { [ catch { b64decode $str } decodedstr ] == 0 and $decodedstr != \"\" } {\n        return $decodedstr\n    } else {\n        log local0.err \"Base64 decoding error for string $str\"\n        return \"\"\n    }\n}\n \n\n   \n\n   \n\n One of my colleagues Brian also did some capacity testing to look at different options and what the highest performance is - through this we realised that going directly to the servers is more performant than sending to a local virtual server, and I also changed the code so that rather than sending, waiting a fixed period and checking the result, the iRule would check in a shorter loop. \n\n   \n\n From this: \n\n   \n\n \nset send_bytes [send -timeout 100 -status send_status $conn_id [HTTP::payload]]\nlog local0.debug \"send_status: $send_status\"\nrecv -timeout 100 -peek -status recv_status $conn_id result\n \n\n   \n\n to this: \n\n   \n\n \nset send_bytes [send -timeout 100 -status send_status $conn_id $payload ]\nlog local0.debug \"Sent $send_bytes Bytes to $member\"\nfor {set i 0} {$i < $totalLoops} {incr i} {\n    recv -timeout $recvTimeout -status recv_status $conn_id result\n    if { $recv_status == \"received\" } {\n        break\n    }\n}\n \n\n   \n\n which gave the best performance. You can see the configuration options around this in the iApp so you can set the total timeout and the checking period. \n\n   \n\n iApp \n\n   \n\n You can see that this iApp creates a simple GUI to allow the modification of the iRule - to add logs, change the destination, timers etc. This is common for us to create to allow simple operation of the iRule as part of the system. \n\n   \n\n \n\n   \n\n Closing Thoughts \n\n   \n\n If I wanted to make this truly scalable, I would consider using Message Routing Framework (MRF) which decouples the message ( ie the DNS request ) from the underlying transport, meaning that we can send wherever and however required, duplicate messages, respond locally or anything else which takes your fancy. As i'm sure you know, the beauty of the BIG-IP platform is the ability to use these features to build any solution required in a short timescale. \n\n   \n\n Hopefully this has given you an insight into what we in F5 Professional Services regularly do, and if you have any questions or suggestions about the DNS over HTTPS iApp or more general Professional Services questions then feel free to message me. \n\n   \n\n   ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"25364","kudosSumWeight":0,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODQ3NTEtMTIzMTlpODcxNzhFOUFCQkI3RUFDNQ?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODQ3NTEtNjk0OWkwMDQ4NDNEMzQ3MTM3QkQ1?revision=1\"}"}}],"totalCount":2,"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-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/community/Navbar-1743097587932","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-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarHamburgerDropdown-1743097587932","value":{"hamburgerLabel":"Side Menu"},"localOverride":false},"CachedAsset:text:en_US-components/community/BrandLogo-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/community/BrandLogo-1743097587932","value":{"logoAlt":"Khoros","themeLogoAlt":"Brand Logo"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarTextLinks-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarTextLinks-1743097587932","value":{"more":"More"},"localOverride":false},"CachedAsset:text:en_US-components/authentication/AuthenticationLink-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/authentication/AuthenticationLink-1743097587932","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-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/nodes/NodeLink-1743097587932","value":{"place":"Place {name}"},"localOverride":false},"CachedAsset:text:en_US-components/tags/TagSubscriptionAction-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/tags/TagSubscriptionAction-1743097587932","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-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageListTabs-1743097587932","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-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/QueryHandler-1743097587932","value":{"title":"Query Handler"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarDropdownToggle-1743097587932","value":{"ariaLabelClosed":"Press the down arrow to open the menu"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/OverflowNav-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/OverflowNav-1743097587932","value":{"toggleText":"More"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageView/MessageViewInline-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageView/MessageViewInline-1743097587932","value":{"bylineAuthor":"{bylineAuthor}","bylineBoard":"{bylineBoard}","anonymous":"Anonymous","place":"Place {bylineBoard}","gotoParent":"Go to parent {name}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Pager/PagerLoadMore-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Pager/PagerLoadMore-1743097587932","value":{"loadMore":"Show More"},"localOverride":false},"CachedAsset:text:en_US-components/customComponent/CustomComponent-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/customComponent/CustomComponent-1743097587932","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-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/users/UserLink-1743097587932","value":{"authorName":"View Profile: {author}","anonymous":"Anonymous"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageSubject-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageSubject-1743097587932","value":{"noSubject":"(no subject)"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageTime-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageTime-1743097587932","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-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/nodes/NodeIcon-1743097587932","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-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageUnreadCount-1743097587932","value":{"unread":"{count} unread","comments":"{count, plural, one { unread comment} other{ unread comments}}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageViewCount-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageViewCount-1743097587932","value":{"textTitle":"{count, plural,one {View} other{Views}}","views":"{count, plural, one{View} other{Views}}"},"localOverride":false},"CachedAsset:text:en_US-components/kudos/KudosCount-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/kudos/KudosCount-1743097587932","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-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageRepliesCount-1743097587932","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-components/messages/MessageBody-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageBody-1743097587932","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-shared/client/components/users/UserAvatar-1743097587932":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/users/UserAvatar-1743097587932","value":{"altText":"{login}'s avatar","altTextGeneric":"User's avatar"},"localOverride":false}}}},"page":"/tags/TagPage/TagPage","query":{"nodeId":"board:TechnicalArticles","tagName":"iApps"},"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","../shared/client/components/common/Pager/PagerLoadMore/PagerLoadMore.tsx","./components/customComponent/CustomComponentContent/HtmlContent.tsx","./components/customComponent/CustomComponentContent/CustomComponentScripts.tsx"],"appGip":true,"scriptLoader":[]}